github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/fastreflection/get.go (about) 1 package fastreflection 2 3 import ( 4 "github.com/cosmos/cosmos-proto/generator" 5 "google.golang.org/protobuf/compiler/protogen" 6 "google.golang.org/protobuf/reflect/protoreflect" 7 ) 8 9 type getGen struct { 10 *generator.GeneratedFile 11 typeName string 12 message *protogen.Message 13 } 14 15 func (g *getGen) generate() { 16 g.genComment() 17 g.P("func (x *", g.typeName, ") Get(descriptor ", protoreflectPkg.Ident("FieldDescriptor"), ") ", protoreflectPkg.Ident("Value"), " {") 18 g.P("switch descriptor.FullName() {") 19 // implement the fastReflectionFeature Get function 20 for _, field := range g.message.Fields { 21 g.P("case \"", field.Desc.FullName(), "\":") 22 g.genFieldGetter(field) 23 } 24 // insert default case which panics 25 g.P("default:") 26 g.genDefaultCase() 27 g.P("}") 28 g.P("}") 29 g.P() 30 } 31 32 func (g *getGen) genComment() { 33 g.P("// Get retrieves the value for a field.") 34 g.P("//") 35 g.P("// For unpopulated scalars, it returns the default value, where") 36 g.P("// the default value of a bytes scalar is guaranteed to be a copy.") 37 g.P("// For unpopulated composite types, it returns an empty, read-only view") 38 g.P("// of the value; to obtain a mutable reference, use Mutable.") 39 } 40 41 func (g *getGen) genFieldGetter(field *protogen.Field) { 42 if field.Oneof != nil { 43 g.genOneofGetter(field) 44 return 45 } 46 47 switch { 48 case field.Desc.IsMap(): 49 g.genMap(field) 50 return 51 case field.Desc.IsList(): 52 g.genList(field) 53 return 54 } 55 56 fieldRef := "x." + field.GoName 57 g.P("value := ", fieldRef) 58 switch field.Desc.Kind() { 59 case protoreflect.BoolKind: 60 g.P("return ", protoreflectPkg.Ident("ValueOfBool"), "(value)") 61 case protoreflect.EnumKind: 62 g.P("return ", protoreflectPkg.Ident("ValueOfEnum"), "((", protoreflectPkg.Ident("EnumNumber"), ")", "(value)", ")") 63 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 64 g.P("return ", protoreflectPkg.Ident("ValueOfInt32"), "(value)") 65 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 66 g.P("return ", protoreflectPkg.Ident("ValueOfUint32"), "(value)") 67 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 68 g.P("return ", protoreflectPkg.Ident("ValueOfInt64"), "(value)") 69 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 70 g.P("return ", protoreflectPkg.Ident("ValueOfUint64"), "(value)") 71 case protoreflect.FloatKind: 72 g.P("return ", protoreflectPkg.Ident("ValueOfFloat32"), "(value)") 73 case protoreflect.DoubleKind: 74 g.P("return ", protoreflectPkg.Ident("ValueOfFloat64"), "(value)") 75 case protoreflect.StringKind: 76 g.P("return ", protoreflectPkg.Ident("ValueOfString"), "(value)") 77 case protoreflect.BytesKind: 78 g.P("return ", protoreflectPkg.Ident("ValueOfBytes"), "(value)") 79 case protoreflect.MessageKind, protoreflect.GroupKind: 80 g.P("return ", protoreflectPkg.Ident("ValueOfMessage"), "(value.ProtoReflect())") 81 } 82 } 83 84 func (g *getGen) genOneofGetter(fd *protogen.Field) { 85 // handle the case in which the oneof field is not set 86 g.P("if x.", fd.Oneof.GoName, " == nil {") 87 switch fd.Desc.Kind() { 88 case protoreflect.MessageKind: 89 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "((*", g.QualifiedGoIdent(fd.Message.GoIdent), ")(nil).ProtoReflect())") 90 default: 91 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "(", zeroValueForField(g.GeneratedFile, fd), ")") 92 } 93 // handle the case in which oneof field is set and it matches our sub-onefield type 94 g.P("} else if v, ok := x.", fd.Oneof.GoName, ".(*", fd.GoIdent, "); ok {") 95 oneofTypeContainerFieldName := fd.GoName // field containing the oneof value 96 switch fd.Desc.Kind() { 97 case protoreflect.MessageKind: // it can be mutable 98 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "(v.", oneofTypeContainerFieldName, ".ProtoReflect())") 99 case protoreflect.EnumKind: 100 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "((", protoreflectPkg.Ident("EnumNumber"), ")(v.", oneofTypeContainerFieldName, "))") 101 default: 102 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "(v.", oneofTypeContainerFieldName, ")") 103 } 104 // handle the case in which the oneof field is set but it does not match our field type 105 g.P("} else {") 106 switch fd.Desc.Kind() { 107 case protoreflect.MessageKind: 108 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "((*", g.QualifiedGoIdent(fd.Message.GoIdent), ")(nil).ProtoReflect())") 109 default: 110 g.P("return ", kindToValueConstructor(fd.Desc.Kind()), "(", zeroValueForField(g.GeneratedFile, fd), ")") 111 } 112 g.P("}") 113 } 114 115 // genDefaultCase generates the default case for field descriptor 116 func (g *getGen) genDefaultCase() { 117 g.P("if descriptor.IsExtension() {") 118 g.P("panic(", fmtPkg.Ident("Errorf"), "(\"proto3 declared messages do not support extensions: ", g.message.Desc.FullName(), "\"))") 119 g.P("}") 120 g.P("panic(fmt.Errorf(\"message ", g.message.Desc.FullName(), " does not contain field %s\", descriptor.FullName()))") 121 } 122 123 // genMap generates the protoreflect.Message.Get for map types 124 func (g *getGen) genMap(field *protogen.Field) { 125 // gen invalid case 126 g.P("if len(x.", field.GoName, ") == 0 {") 127 g.P("return ", protoreflectPkg.Ident("ValueOfMap"), "(&", mapTypeName(field), "{})") 128 g.P("}") 129 // gen valid case 130 g.P("mapValue := &", mapTypeName(field), "{m: &x.", field.GoName, "}") 131 g.P("return ", protoreflectPkg.Ident("ValueOfMap"), "(mapValue)") 132 } 133 134 func (g *getGen) genList(field *protogen.Field) { 135 // gen invalid case 136 g.P("if len(x.", field.GoName, ") == 0 {") 137 g.P("return ", protoreflectPkg.Ident("ValueOfList"), "(&", listTypeName(field), "{})") 138 g.P("}") 139 // gen valid case 140 g.P("listValue := &", listTypeName(field), "{list: &x.", field.GoName, "}") 141 g.P("return ", protoreflectPkg.Ident("ValueOfList"), "(listValue)") 142 } 143 144 // genGet generates the implementation for protoreflect.Message.Get 145 func (g *fastGenerator) genGet() { 146 (&getGen{ 147 GeneratedFile: g.GeneratedFile, 148 typeName: g.typeName, 149 message: g.message, 150 }).generate() 151 }