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  }