Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Well known type wrappers #99

Merged
merged 7 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Contributing to vtProtobuf

## Workflow

For all contributors, we recommend the standard [GitHub flow](https://guides.github.com/introduction/flow/)
based on [forking and pull requests](https://guides.github.com/activities/forking/).

For significant changes, please [create an issue](https://github.com/planetscale/vtprotobuf/issues)
to let everyone know what you're planning to work on, and to track progress and design decisions.

## Development

### Protobuf version upgrade

1. Bump protobuf version in [./protobuf.sh](./protobuf.sh)) (PROTOBUF_VERSION variable).
1. Run `./protobuf.sh` to download and build protobuf.
1. Run `make genall` to regenerate proto files with a new compiler version, including well-known types.
42 changes: 34 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
export GOBIN=$(PWD)/bin
export PROTOBUF_ROOT=$(PWD)/_vendor/protobuf-21.12

.PHONY: install test gen-conformance gen-include genall
.PHONY: install test gen-conformance gen-include gen-wkt genall bin/protoc-gen-go bin/protoc-gen-go-vtproto

install:
go install -tags protolegacy google.golang.org/protobuf/cmd/protoc-gen-go
install: bin/protoc-gen-go-vtproto bin/protoc-gen-go

bin/protoc-gen-go-vtproto:
go install -tags protolegacy ./cmd/protoc-gen-go-vtproto
# go install -tags protolegacy github.com/gogo/protobuf/protoc-gen-gofast

gen-conformance:
bin/protoc-gen-go:
go install -tags protolegacy google.golang.org/protobuf/cmd/protoc-gen-go

gen-conformance: install
$(PROTOBUF_ROOT)/src/protoc \
--proto_path=$(PROTOBUF_ROOT) \
--go_out=conformance --plugin protoc-gen-go="${GOBIN}/protoc-gen-go" \
Expand All @@ -24,15 +27,28 @@ gen-conformance:
src/google/protobuf/test_messages_proto3.proto \
conformance/conformance.proto

gen-include:
gen-include: bin/protoc-gen-go
$(PROTOBUF_ROOT)/src/protoc \
--proto_path=include \
--go_out=include --plugin protoc-gen-go="${GOBIN}/protoc-gen-go" \
-I$(PROTOBUF_ROOT)/src \
github.com/planetscale/vtprotobuf/vtproto/ext.proto
mv include/github.com/planetscale/vtprotobuf/vtproto/*.go ./vtproto

gen-testproto:
gen-wkt: bin/protoc-gen-go-vtproto
$(PROTOBUF_ROOT)/src/protoc \
-I$(PROTOBUF_ROOT)/src \
--plugin protoc-gen-go-vtproto="${GOBIN}/protoc-gen-go-vtproto" \
--go-vtproto_out=. \
--go-vtproto_opt=module=google.golang.org/protobuf,wrap=true \
$(PROTOBUF_ROOT)/src/google/protobuf/any.proto \
$(PROTOBUF_ROOT)/src/google/protobuf/duration.proto \
$(PROTOBUF_ROOT)/src/google/protobuf/empty.proto \
$(PROTOBUF_ROOT)/src/google/protobuf/field_mask.proto \
$(PROTOBUF_ROOT)/src/google/protobuf/timestamp.proto \
$(PROTOBUF_ROOT)/src/google/protobuf/wrappers.proto

gen-testproto: gen-wkt-testproto install
$(PROTOBUF_ROOT)/src/protoc \
--proto_path=testproto \
--proto_path=include \
Expand All @@ -47,7 +63,17 @@ gen-testproto:
testproto/proto2/scalars.proto \
|| exit 1;

genall: install gen-include gen-conformance gen-testproto
gen-wkt-testproto: install
$(PROTOBUF_ROOT)/src/protoc \
--proto_path=testproto \
--proto_path=include \
--go_out=. --plugin protoc-gen-go="${GOBIN}/protoc-gen-go" \
--go-vtproto_out=allow-empty=true:. --plugin protoc-gen-go-vtproto="${GOBIN}/protoc-gen-go-vtproto" \
-I$(PROTOBUF_ROOT)/src \
testproto/wkt/wkt.proto \
|| exit 1;

genall: gen-include gen-conformance gen-testproto gen-wkt

test: install gen-conformance
go test -short ./...
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ The following features can be generated:
7. (Optional) Switch your RPC framework to use the optimized helpers (see following sections)
## Well-known types
By default, `vtprotobuf` will detect ProtoBuf [well-known types](https://protobuf.dev/reference/protobuf/google.protobuf/) embedded in your own Messages and generate optimized code to marshal and unmarshal them.
In order to access the optimized code for these types, your `_vtproto.pb.go` files will have a dependency on this Go package. If this is not acceptable, you can disable well-known types with `--go-vtproto_opt=wkt=false`.
## Using the optimized code with RPC frameworks
The `protoc-gen-go-vtproto` compiler does not overwrite any of the default marshalling or unmarshalling code for your ProtoBuf objects. Instead, it generates helper methods that can be called explicitly to opt-in to faster (de)serialization.
Expand Down
62 changes: 11 additions & 51 deletions cmd/protoc-gen-go-vtproto/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"flag"
"fmt"
"strings"

_ "github.com/planetscale/vtprotobuf/features/clone"
Expand All @@ -15,64 +14,25 @@ import (
"github.com/planetscale/vtprotobuf/generator"

"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/pluginpb"
)

type ObjectSet map[protogen.GoIdent]bool

func (o ObjectSet) String() string {
return fmt.Sprintf("%#v", o)
}

func (o ObjectSet) Set(s string) error {
idx := strings.LastIndexByte(s, '.')
if idx < 0 {
return fmt.Errorf("invalid object name: %q", s)
}

ident := protogen.GoIdent{
GoImportPath: protogen.GoImportPath(s[0:idx]),
GoName: s[idx+1:],
}
o[ident] = true
return nil
}

func main() {
var allowEmpty bool
var cfg generator.Config
var features string
poolable := make(ObjectSet)

var f flag.FlagSet
f.BoolVar(&allowEmpty, "allow-empty", false, "allow generation of empty files")
f.Var(poolable, "pool", "use memory pooling for this object")
f.BoolVar(&cfg.AllowEmpty, "allow-empty", false, "allow generation of empty files")
f.Var(&cfg.Poolable, "pool", "use memory pooling for this object")
f.BoolVar(&cfg.Wrap, "wrap", false, "generate wrapper types")
f.BoolVar(&cfg.WellKnownTypes, "wkt", true, "generate optimized code for well-known types")
f.StringVar(&features, "features", "all", "list of features to generate (separated by '+')")

protogen.Options{ParamFunc: f.Set}.Run(func(plugin *protogen.Plugin) error {
return generateAllFiles(plugin, strings.Split(features, "+"), poolable, allowEmpty)
})
}

var SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)

func generateAllFiles(plugin *protogen.Plugin, featureNames []string, poolable ObjectSet, allowEmpty bool) error {
ext := &generator.Extensions{Poolable: poolable}
gen, err := generator.NewGenerator(plugin.Files, featureNames, ext)
if err != nil {
return err
}

for _, file := range plugin.Files {
if !file.Generate {
continue
gen, err := generator.NewGenerator(plugin, strings.Split(features, "+"), &cfg)
if err != nil {
return err
}

gf := plugin.NewGeneratedFile(file.GeneratedFilenamePrefix+"_vtproto.pb.go", file.GoImportPath)
if !gen.GenerateFile(gf, file) && !allowEmpty {
gf.Skip()
}
}

plugin.SupportedFeatures = SupportedFeatures
return nil
gen.Generate()
return nil
})
}
Loading