github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/fastreflection/has.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  const (
    10  	mathPkg = protogen.GoImportPath("math")
    11  )
    12  
    13  // fields are not populated if
    14  // if scalar: value != zero value
    15  // if msg value != nil
    16  // if list len(list) != 0
    17  // if map len(map) != 0
    18  // if oneof: oneof != nil (if oneof is scalar do we need to check it??)
    19  // if bytes: len(bytes) != 0
    20  type hasGen struct {
    21  	*generator.GeneratedFile
    22  	typeName string
    23  	message  *protogen.Message
    24  }
    25  
    26  func (g *hasGen) genComments() {
    27  	g.P("// Has reports whether a field is populated.")
    28  	g.P("//")
    29  	g.P("// Some fields have the property of nullability where it is possible to")
    30  	g.P("// distinguish between the default value of a field and whether the field")
    31  	g.P("// was explicitly populated with the default value. Singular message fields,")
    32  	g.P("// member fields of a oneof, and proto2 scalar fields are nullable. Such")
    33  	g.P("// fields are populated only if explicitly set.")
    34  	g.P("//")
    35  	g.P("// In other cases (aside from the nullable cases above),")
    36  	g.P("// a proto3 scalar field is populated if it contains a non-zero value, and")
    37  	g.P("// a repeated field is populated if it is non-empty.")
    38  }
    39  
    40  func (g *hasGen) generate() {
    41  	g.genComments()
    42  	g.P("func (x *", g.typeName, ") Has(fd ", protoreflectPkg.Ident("FieldDescriptor"), ") bool {")
    43  	g.P("switch fd.FullName() {")
    44  	for _, field := range g.message.Fields {
    45  		g.genField(field)
    46  	}
    47  	g.P("default:")
    48  	g.P("if fd.IsExtension() {")
    49  	g.P("panic(", fmtPkg.Ident("Errorf"), "(\"proto3 declared messages do not support extensions: ", g.message.Desc.FullName(), "\"))")
    50  	g.P("}")
    51  	g.P("panic(fmt.Errorf(\"message ", g.message.Desc.FullName(), " does not contain field %s\", fd.FullName()))")
    52  	g.P("}")
    53  	g.P("}")
    54  }
    55  
    56  func (g *hasGen) genField(field *protogen.Field) {
    57  	g.P("case \"", field.Desc.FullName(), "\":")
    58  	if field.Desc.HasPresence() || field.Desc.IsList() || field.Desc.IsMap() || field.Desc.Kind() == protoreflect.BytesKind {
    59  		g.genNullable(field)
    60  		return
    61  	}
    62  
    63  	switch field.Desc.Kind() {
    64  	case protoreflect.FloatKind:
    65  		g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(float64(x.", field.GoName, "))")
    66  	case protoreflect.DoubleKind:
    67  		g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field), " || ", mathPkg.Ident("Signbit"), "(x.", field.GoName, ")")
    68  	default:
    69  		g.P("return x.", field.GoName, " != ", zeroValueForField(nil, field))
    70  	}
    71  
    72  }
    73  
    74  func (g *hasGen) genNullable(field *protogen.Field) {
    75  	switch {
    76  	case field.Desc.ContainingOneof() != nil:
    77  		// case oneof is nil
    78  		g.P("if x.", field.Oneof.GoName, " == nil {")
    79  		g.P("return false")
    80  		// if oneof is not nil we need to try cast it to the concrete type
    81  		// and if it succeeds then it means the message has the field
    82  		g.P("} else if _, ok := x.", field.Oneof.GoName, ".(*", field.GoIdent, "); ok {")
    83  		g.P("return true")
    84  		g.P("} else { ")
    85  		g.P("return false")
    86  		g.P("}")
    87  	case field.Desc.IsMap(), field.Desc.IsList(), field.Desc.Kind() == protoreflect.BytesKind:
    88  		g.P("return len(x.", field.GoName, ") != 0")
    89  	case field.Desc.Kind() == protoreflect.MessageKind:
    90  		g.P("return x.", field.GoName, " != nil")
    91  	default:
    92  		panic("unknown case")
    93  	}
    94  }