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 } diff --git a/pkg/api/unversioned/time.go b/pkg/api/unversioned/time.go index 1180e6bd14f..df94bbe72c8 100644 --- a/pkg/api/unversioned/time.go +++ b/pkg/api/unversioned/time.go @@ -28,8 +28,9 @@ import ( // of the factory methods that the time package offers. // // +protobuf.options.marshal=false +// +protobuf.as=Timestamp type Time struct { - time.Time `protobuf:"Timestamp,1,req,name=time"` + time.Time `protobuf:"-"` } // NewTime returns a wrapped instance of the provided time diff --git a/pkg/api/unversioned/time_proto.go b/pkg/api/unversioned/time_proto.go index 6d6fe5d4e7b..5ca0edcdf05 100644 --- a/pkg/api/unversioned/time_proto.go +++ b/pkg/api/unversioned/time_proto.go @@ -22,15 +22,9 @@ import ( "time" ) -// ProtoTime is a struct that is equivalent to Time, but intended for +// Timestamp is a struct that is equivalent to Time, but intended for // protobuf marshalling/unmarshalling. It is generated into a serialization // that matches Time. Do not use in Go structs. -type ProtoTime struct { - // Represents the time of an event. - Timestamp Timestamp `json:"timestamp"` -} - -// Timestamp is a protobuf Timestamp compatible representation of time.Time type Timestamp struct { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to @@ -39,20 +33,18 @@ type Timestamp struct { // Non-negative fractions of a second at nanosecond resolution. Negative // second values with fractions must still have non-negative nanos values // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. + // inclusive. This field may be limited in precision depending on context. Nanos int32 `json:"nanos"` } -// ProtoTime returns the Time as a new ProtoTime value. -func (m *Time) ProtoTime() *ProtoTime { +// Timestamp returns the Time as a new Timestamp value. +func (m *Time) ProtoTime() *Timestamp { if m == nil { - return &ProtoTime{} + return &Timestamp{} } - return &ProtoTime{ - Timestamp: Timestamp{ - Seconds: m.Time.Unix(), - Nanos: int32(m.Time.Nanosecond()), - }, + return &Timestamp{ + Seconds: m.Time.Unix(), + Nanos: int32(m.Time.Nanosecond()), } } @@ -61,11 +53,11 @@ func (m *Time) Size() (n int) { return m.ProtoTime().Size() } // Reset implements the protobuf marshalling interface. func (m *Time) Unmarshal(data []byte) error { - p := ProtoTime{} + p := Timestamp{} if err := p.Unmarshal(data); err != nil { return err } - m.Time = time.Unix(p.Timestamp.Seconds, int64(p.Timestamp.Nanos)) + m.Time = time.Unix(p.Seconds, int64(p.Nanos)) return nil }