Skip to content

Commit

Permalink
Merge pull request #99 from planetscale/well-known-type-wrappers
Browse files Browse the repository at this point in the history
Well known type wrappers
  • Loading branch information
vmg committed Oct 2, 2023
2 parents a30b51d + f080268 commit d49cd97
Show file tree
Hide file tree
Showing 23 changed files with 5,645 additions and 1,819 deletions.
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

0 comments on commit d49cd97

Please sign in to comment.