Commit 529bd2bf authored by Clayton Coleman's avatar Clayton Coleman

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.
parent fd192309
......@@ -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
}
......
......@@ -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
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment