Skip to content

Commit

Permalink
feat: avoid field/method name clashes for fast reflection wrappers
Browse files Browse the repository at this point in the history
Solve the clashes by introducing a level of indirection, replacing

type fastReflection_A A

with

type fastReflection_A struct {
 x *A
}

Updates cosmos#50
  • Loading branch information
elias-orijtech committed Mar 24, 2023
1 parent 537ea83 commit 5c8d30f
Show file tree
Hide file tree
Showing 15 changed files with 1,204 additions and 1,180 deletions.
10 changes: 5 additions & 5 deletions internal/features/fastreflection/clear.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (g *clearGen) genComments() {

func (g *clearGen) generate() {
g.genComments()
g.P("func (x *", g.typeName, ") Clear(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") {")
g.P("func (x ", g.typeName, ") Clear(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") {")
g.P("switch fd.FullName() {")
for _, field := range g.message.Fields {
g.genField(field)
Expand All @@ -51,17 +51,17 @@ func (g *clearGen) genField(field *protogen.Field) {
return
}

g.P("x.", field.GoName, " = ", zeroValueForField(nil, field))
g.P("x.x.", field.GoName, " = ", zeroValueForField(nil, field))
}

func (g *clearGen) genNullable(field *protogen.Field) {
switch {
case field.Desc.ContainingOneof() != nil:
g.P("x.", field.Oneof.GoName, " = nil")
g.P("x.x.", field.Oneof.GoName, " = nil")
case field.Desc.IsMap(), field.Desc.IsList(), field.Desc.Kind() == protoreflect.BytesKind:
g.P("x.", field.GoName, " = nil")
g.P("x.x.", field.GoName, " = nil")
case field.Desc.Kind() == protoreflect.MessageKind:
g.P(" x.", field.GoName, " = nil")
g.P("x.x.", field.GoName, " = nil")
default:
panic("unknown case")
}
Expand Down
16 changes: 8 additions & 8 deletions internal/features/fastreflection/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type getGen struct {

func (g *getGen) generate() {
g.genComment()
g.P("func (x *", g.typeName, ") Get(descriptor ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("func (x ", g.typeName, ") Get(descriptor ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("switch descriptor.FullName() {")
// implement the fastReflectionFeature Get function
for _, field := range g.message.Fields {
Expand Down Expand Up @@ -53,7 +53,7 @@ func (g *getGen) genFieldGetter(field *protogen.Field) {
return
}

fieldRef := "x." + field.GoName
fieldRef := "x.x." + field.GoName
g.P("value := ", fieldRef)
switch field.Desc.Kind() {
case protoreflect.BoolKind:
Expand Down Expand Up @@ -83,15 +83,15 @@ func (g *getGen) genFieldGetter(field *protogen.Field) {

func (g *getGen) genOneofGetter(fd *protogen.Field) {
// handle the case in which the oneof field is not set
g.P("if x.", fd.Oneof.GoName, " == nil {")
g.P("if x.x.", fd.Oneof.GoName, " == nil {")
switch fd.Desc.Kind() {
case protoreflect.MessageKind:
g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "((*", g.QualifiedGoIdent(fd.Message.GoIdent), ")(nil).ProtoReflect())")
default:
g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "(", zeroValueForField(g.GeneratedFile, fd), ")")
}
// handle the case in which oneof field is set and it matches our sub-onefield type
g.P("} else if v, ok := x.", fd.Oneof.GoName, ".(*", fd.GoIdent, "); ok {")
g.P("} else if v, ok := x.x.", fd.Oneof.GoName, ".(*", fd.GoIdent, "); ok {")
oneofTypeContainerFieldName := fd.GoName // field containing the oneof value
switch fd.Desc.Kind() {
case protoreflect.MessageKind: // it can be mutable
Expand Down Expand Up @@ -123,21 +123,21 @@ func (g *getGen) genDefaultCase() {
// genMap generates the protoreflect.Message.Get for map types
func (g *getGen) genMap(field *protogen.Field) {
// gen invalid case
g.P("if len(x.", field.GoName, ") == 0 {")
g.P("if len(x.x.", field.GoName, ") == 0 {")
g.P("return ", protoreflectPkg.Ident("ValueOfMap"), "(&", mapTypeName(field), "{})")
g.P("}")
// gen valid case
g.P("mapValue := &", mapTypeName(field), "{m: &x.", field.GoName, "}")
g.P("mapValue := &", mapTypeName(field), "{m: &x.x.", field.GoName, "}")
g.P("return ", protoreflectPkg.Ident("ValueOfMap"), "(mapValue)")
}

func (g *getGen) genList(field *protogen.Field) {
// gen invalid case
g.P("if len(x.", field.GoName, ") == 0 {")
g.P("if len(x.x.", field.GoName, ") == 0 {")
g.P("return ", protoreflectPkg.Ident("ValueOfList"), "(&", listTypeName(field), "{})")
g.P("}")
// gen valid case
g.P("listValue := &", listTypeName(field), "{list: &x.", field.GoName, "}")
g.P("listValue := &", listTypeName(field), "{list: &x.x.", field.GoName, "}")
g.P("return ", protoreflectPkg.Ident("ValueOfList"), "(listValue)")
}

Expand Down
16 changes: 8 additions & 8 deletions internal/features/fastreflection/has.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (g *hasGen) genComments() {

func (g *hasGen) generate() {
g.genComments()
g.P("func (x *", g.typeName, ") Has(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") bool {")
g.P("func (x ", g.typeName, ") Has(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") bool {")
g.P("switch fd.FullName() {")
for _, field := range g.message.Fields {
g.genField(field)
Expand All @@ -62,11 +62,11 @@ func (g *hasGen) genField(field *protogen.Field) {

switch field.Desc.Kind() {
case protoreflect.FloatKind:
g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(float64(x.", field.GoName, "))")
g.P("return x.x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(float64(x.x.", field.GoName, "))")
case protoreflect.DoubleKind:
g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(x.", field.GoName, ")")
g.P("return x.x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(x.x.", field.GoName, ")")
default:
g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field))
g.P("return x.x.", field.GoName, " != ", zeroValueForField(nil, field))
}

}
Expand All @@ -75,19 +75,19 @@ func (g *hasGen) genNullable(field *protogen.Field) {
switch {
case field.Desc.ContainingOneof() != nil:
// case oneof is nil
g.P("if x.", field.Oneof.GoName, " == nil {")
g.P("if x.x.", field.Oneof.GoName, " == nil {")
g.P("return false")
// if oneof is not nil we need to try cast it to the concrete type
// and if it succeeds then it means the message has the field
g.P("} else if _, ok := x.", field.Oneof.GoName, ".(*", field.GoIdent, "); ok {")
g.P("} else if _, ok := x.x.", field.Oneof.GoName, ".(*", field.GoIdent, "); ok {")
g.P("return true")
g.P("} else { ")
g.P("return false")
g.P("}")
case field.Desc.IsMap(), field.Desc.IsList(), field.Desc.Kind() == protoreflect.BytesKind:
g.P("return len(x.", field.GoName, ") != 0")
g.P("return len(x.x.", field.GoName, ") != 0")
case field.Desc.Kind() == protoreflect.MessageKind:
g.P("return x.", field.GoName, " != nil")
g.P("return x.x.", field.GoName, " != nil")
default:
panic("unknown case")
}
Expand Down
28 changes: 14 additions & 14 deletions internal/features/fastreflection/mutable.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type mutableGen struct {

func (g *mutableGen) generate() {
g.genComment()
g.P("func (x *", g.typeName, ") Mutable(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("func (x ", g.typeName, ") Mutable(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("switch fd.FullName() {")
// we first output all the fields that are mutable
for _, field := range g.message.Fields {
Expand Down Expand Up @@ -77,38 +77,38 @@ func (g *mutableGen) genField(field *protogen.Field) {
switch {
case field.Desc.IsMap():
// if map is invalid then we make it valid
g.P("if x.", field.GoName, " == nil {")
g.P("x.", field.GoName, " = make(map[", getGoType(g.GeneratedFile, field.Message.Fields[0]), "]", getGoType(g.GeneratedFile, field.Message.Fields[1]), ")")
g.P("if x.x.", field.GoName, " == nil {")
g.P("x.x.", field.GoName, " = make(map[", getGoType(g.GeneratedFile, field.Message.Fields[0]), "]", getGoType(g.GeneratedFile, field.Message.Fields[1]), ")")
g.P("}")
// return value of map
g.P("value := &", mapTypeName(field), "{m: &x.", field.GoName, "}")
g.P("value := &", mapTypeName(field), "{m: &x.x.", field.GoName, "}")
g.P("return ", protoreflectPkg.Ident("ValueOfMap"), "(value)")
case field.Desc.IsList():
g.P("if x.", field.GoName, " == nil {")
g.P("x.", field.GoName, " = []", getGoType(g.GeneratedFile, field), "{}")
g.P("if x.x.", field.GoName, " == nil {")
g.P("x.x.", field.GoName, " = []", getGoType(g.GeneratedFile, field), "{}")
g.P("}")
g.P("value := &", listTypeName(field), "{list: &x.", field.GoName, "}")
g.P("value := &", listTypeName(field), "{list: &x.x.", field.GoName, "}")
g.P("return ", protoreflectPkg.Ident("ValueOfList"), "(value)")
case field.Desc.Kind() == protoreflect.MessageKind:
g.P("if x.", field.GoName, " == nil {")
g.P("x.", field.GoName, " = new(", g.QualifiedGoIdent(field.Message.GoIdent), ")")
g.P("if x.x.", field.GoName, " == nil {")
g.P("x.x.", field.GoName, " = new(", g.QualifiedGoIdent(field.Message.GoIdent), ")")
g.P("}")
g.P("return ", protoreflectPkg.Ident("ValueOfMessage"), "(x.", field.GoName, ".ProtoReflect())")
g.P("return ", protoreflectPkg.Ident("ValueOfMessage"), "(x.x.", field.GoName, ".ProtoReflect())")
default:
panic("unreachable")
}
}

func (g *mutableGen) genOneof(field *protogen.Field) {
// if the oneof is nil then we just create a new instance of the object and return it
g.P("if x.", field.Oneof.GoName, " == nil {")
g.P("if x.x.", field.Oneof.GoName, " == nil {")
g.P("value := &", g.QualifiedGoIdent(field.Message.GoIdent), "{}")
g.P("oneofValue := &", g.QualifiedGoIdent(field.GoIdent), "{", field.GoName, ": value}")
g.P("x.", field.Oneof.GoName, " = oneofValue")
g.P("x.x.", field.Oneof.GoName, " = oneofValue")
g.P("return ", protoreflectPkg.Ident("ValueOfMessage"), "(value.ProtoReflect())")
g.P("}")
// if the oneof is not nil,
g.P("switch m := x.", field.Oneof.GoName, ".(type) {")
g.P("switch m := x.x.", field.Oneof.GoName, ".(type) {")
// we check if the type matches the oneof type of the field
g.P("case *", g.QualifiedGoIdent(field.GoIdent), ":")
// if it does we return it
Expand All @@ -117,7 +117,7 @@ func (g *mutableGen) genOneof(field *protogen.Field) {
g.P("default:")
g.P("value := &", g.QualifiedGoIdent(field.Message.GoIdent), "{}")
g.P("oneofValue := &", g.QualifiedGoIdent(field.GoIdent), "{", field.GoName, ": value}")
g.P("x.", field.Oneof.GoName, " = oneofValue")
g.P("x.x.", field.Oneof.GoName, " = oneofValue")
g.P("return ", protoreflectPkg.Ident("ValueOfMessage"), "(value.ProtoReflect())")
g.P("}")

Expand Down
2 changes: 1 addition & 1 deletion internal/features/fastreflection/new_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type newFieldGen struct {

func (g *newFieldGen) generate() {
g.genComment()
g.P("func (x *", g.typeName, ") NewField(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("func (x ", g.typeName, ") NewField(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {")
g.P("switch fd.FullName() {")
for _, field := range g.message.Fields {
g.P("case \"", field.Desc.FullName(), "\":")
Expand Down
34 changes: 18 additions & 16 deletions internal/features/fastreflection/proto_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ func (g *fastGenerator) genMessageType() {

func (g *fastGenerator) generateReflectionType() {
// gen interface assertion
g.P("var _ ", protoreflectPkg.Ident("Message"), " = (*", g.typeName, ")(nil)")
g.P("var _ ", protoreflectPkg.Ident("Message"), " = ", g.typeName, "{}")
g.P()
// gen type
g.P("type ", g.typeName, " ", g.message.GoIdent.GoName)
g.P("type ", g.typeName, " struct {")
g.P("x *", g.message.GoIdent.GoName)
g.P("}")
// gen msg implementation
g.P("func (x *", g.message.GoIdent.GoName, ") ProtoReflect() ", protoreflectPkg.Ident("Message"), "{")
g.P("return (*", g.typeName, ")(x)")
g.P("return ", g.typeName, "{x: x}")
g.P("}")
g.P()

Expand Down Expand Up @@ -154,7 +156,7 @@ func (g *fastGenerator) generateReflectionType() {
func (g *fastGenerator) genDescriptor() {
g.P("// Descriptor returns message descriptor, which contains only the protobuf")
g.P("// type information for the message.")
g.P("func (x *", g.typeName, ") Descriptor() ", protoreflectPkg.Ident("MessageDescriptor"), " {")
g.P("func (x ", g.typeName, ") Descriptor() ", protoreflectPkg.Ident("MessageDescriptor"), " {")
g.P("return ", messageDescriptorName(g.message))
g.P("}")
g.P()
Expand All @@ -164,25 +166,25 @@ func (g *fastGenerator) genType() {
g.P("// Type returns the message type, which encapsulates both Go and protobuf")
g.P("// type information. If the Go type information is not needed,")
g.P("// it is recommended that the message descriptor be used instead.")
g.P("func (x *", g.typeName, ") Type() ", protoreflectPkg.Ident("MessageType"), " {")
g.P("func (x ", g.typeName, ") Type() ", protoreflectPkg.Ident("MessageType"), " {")
g.P("return ", messageTypeNameVar(g.message))
g.P("}")
g.P()
}

func (g *fastGenerator) genNew() {
g.P("// New returns a newly allocated and mutable empty message.")
g.P("func (x *", g.typeName, ") New() ", protoreflectPkg.Ident("Message"), " {")
g.P("return new(", g.typeName, ")")
g.P("func (x ", g.typeName, ") New() ", protoreflectPkg.Ident("Message"), " {")
g.P("return ", g.typeName, "{x: new(", g.message.GoIdent, ")}")
g.P("}")
g.P()
}

func (g *fastGenerator) genInterface() {
g.P("// Interface unwraps the message reflection interface and")
g.P("// returns the underlying ProtoMessage interface.")
g.P("func (x *", g.typeName, ") Interface() ", protoreflectPkg.Ident("ProtoMessage"), " {")
g.P("return (*", g.message.GoIdent, ")(x)")
g.P("func (x ", g.typeName, ") Interface() ", protoreflectPkg.Ident("ProtoMessage"), " {")
g.P("return x.x")
g.P("}")
g.P()
}
Expand Down Expand Up @@ -251,8 +253,8 @@ func (g *fastGenerator) genGetUnknown() {
g.P("// GetUnknown retrieves the entire list of unknown fields.")
g.P("// The caller may only mutate the contents of the RawFields")
g.P("// if the mutated bytes are stored back into the message with SetUnknown.")
g.P("func (x *", g.typeName, ") GetUnknown() ", protoreflectPkg.Ident("RawFields"), " {")
g.P("return x.unknownFields")
g.P("func (x ", g.typeName, ") GetUnknown() ", protoreflectPkg.Ident("RawFields"), " {")
g.P("return x.x.unknownFields")
g.P("}")
g.P()
}
Expand All @@ -265,8 +267,8 @@ func (g *fastGenerator) genSetUnknown() {
g.P("// An empty RawFields may be passed to clear the fields.")
g.P("//")
g.P("// SetUnknown is a mutating operation and unsafe for concurrent use.")
g.P("func (x *", g.typeName, ") SetUnknown(fields ", protoreflectPkg.Ident("RawFields"), ") {")
g.P("x.unknownFields = fields")
g.P("func (x ", g.typeName, ") SetUnknown(fields ", protoreflectPkg.Ident("RawFields"), ") {")
g.P("x.x.unknownFields = fields")
g.P("}")
g.P()
}
Expand All @@ -281,8 +283,8 @@ func (g *fastGenerator) genIsValid() {
g.P("// Validity is not part of the protobuf data model, and may not")
g.P("// be preserved in marshaling or other operations.")

g.P("func (x *", g.typeName, ") IsValid() bool {")
g.P("return x != nil")
g.P("func (x ", g.typeName, ") IsValid() bool {")
g.P("return x.x != nil")
g.P("}")
g.P()
}
Expand All @@ -296,7 +298,7 @@ func (g *fastGenerator) genProtoMethods() {
g.P("// The returned methods type is identical to")
g.P(`// "google.golang.org/protobuf/runtime/protoiface".Methods.`)
g.P("// Consult the protoiface package documentation for details.")
g.P("func (*", g.typeName, ") ProtoMethods() *", protoifacePkg.Ident("Methods"), " {")
g.P("func (", g.typeName, ") ProtoMethods() *", protoifacePkg.Ident("Methods"), " {")
g.P("return ", varName)
g.P("}")

Expand Down
Loading

0 comments on commit 5c8d30f

Please sign in to comment.