From 529bd2bf988e653b078b7aca2c5559d951cc3033 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Mon, 4 Apr 2016 23:00:35 -0400 Subject: [PATCH] Support protobuf.as=Message for aliasing In order to allow a Go type to have a different internal representation, provide the comment `// +protobuf.as=MESSAGENAME` which substitutes the current message's members with the named message's members. Used by the unversioned.Time type to have the same fields as unversioned.Timestamp and to have an alternate serialization. --- .../go-to-protobuf/protobuf/generator.go | 34 +++++++++++++++---- .../go2idl/go-to-protobuf/protobuf/namer.go | 6 +++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/cmd/libs/go2idl/go-to-protobuf/protobuf/generator.go b/cmd/libs/go2idl/go-to-protobuf/protobuf/generator.go index e81c8140021..5d1a8320013 100644 --- a/cmd/libs/go2idl/go-to-protobuf/protobuf/generator.go +++ b/cmd/libs/go2idl/go-to-protobuf/protobuf/generator.go @@ -135,8 +135,9 @@ func (g *genProtoIDL) GenerateType(c *generator.Context, t *types.Type, w io.Wri sw := generator.NewSnippetWriter(w, c, "$", "$") b := bodyGen{ locator: &protobufLocator{ - namer: c.Namers["proto"].(ProtobufFromGoNamer), - tracker: g.imports, + namer: c.Namers["proto"].(ProtobufFromGoNamer), + tracker: g.imports, + universe: c.Universe, localGoPackage: g.localGoPackage.Package, }, @@ -164,12 +165,14 @@ type ProtobufFromGoNamer interface { type ProtobufLocator interface { ProtoTypeFor(t *types.Type) (*types.Type, error) + GoTypeForName(name types.Name) *types.Type CastTypeName(name types.Name) string } type protobufLocator struct { - namer ProtobufFromGoNamer - tracker namer.ImportTracker + namer ProtobufFromGoNamer + tracker namer.ImportTracker + universe types.Universe localGoPackage string } @@ -183,6 +186,13 @@ func (p protobufLocator) CastTypeName(name types.Name) string { return name.String() } +func (p protobufLocator) GoTypeForName(name types.Name) *types.Type { + if len(name.Package) == 0 { + name.Package = p.localGoPackage + } + return p.universe.Type(name) +} + // ProtoTypeFor locates a Protobuf type for the provided Go type (if possible). func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) { switch { @@ -231,6 +241,7 @@ func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { return nil } + var alias *types.Type var fields []protoField options := []string{} allOptions := types.ExtractCommentTags("+", b.t.CommentLines) @@ -254,6 +265,14 @@ func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { options = append(options, fmt.Sprintf("%s = %s", key, v)) } } + // protobuf.as allows a type to have the same message contents as another Go type + case k == "protobuf.as": + fields = nil + if alias = b.locator.GoTypeForName(types.Name{Name: v}); alias == nil { + return fmt.Errorf("type %v references alias %q which does not exist", b.t, v) + } + // protobuf.embed instructs the generator to use the named type in this package + // as an embedded message. case k == "protobuf.embed": fields = []protoField{ { @@ -270,10 +289,13 @@ func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { } } } + if alias == nil { + alias = b.t + } // If we don't explicitly embed anything, generate fields by traversing fields. if fields == nil { - memberFields, err := membersToFields(b.locator, b.t, b.localPackage, b.omitFieldTypes) + memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes) if err != nil { return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) } @@ -454,7 +476,7 @@ func memberTypeToProtobufField(locator ProtobufLocator, field *protoField, t *ty // protobufTagToField extracts information from an existing protobuf tag func protobufTagToField(tag string, field *protoField, m types.Member, t *types.Type, localPackage types.Name) error { - if len(tag) == 0 { + if len(tag) == 0 || tag == "-" { return nil } diff --git a/cmd/libs/go2idl/go-to-protobuf/protobuf/namer.go b/cmd/libs/go2idl/go-to-protobuf/protobuf/namer.go index 662206c0e5c..9e2b9853462 100644 --- a/cmd/libs/go2idl/go-to-protobuf/protobuf/namer.go +++ b/cmd/libs/go2idl/go-to-protobuf/protobuf/namer.go @@ -131,7 +131,11 @@ func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global continue } field := &protoField{} - if err := protobufTagToField(reflect.StructTag(m.Tags).Get("protobuf"), field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil { + tag := reflect.StructTag(m.Tags).Get("protobuf") + if tag == "-" { + continue + } + if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil { assignGoTypeToProtoPackage(p, field.Type, local, global) continue }