github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/fastreflection/range.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 rangeGen struct {
    10  	*generator.GeneratedFile
    11  	typeName string
    12  	message  *protogen.Message
    13  
    14  	processedOneofs map[string]struct{}
    15  }
    16  
    17  func (g *rangeGen) generate() {
    18  	g.processedOneofs = map[string]struct{}{}
    19  
    20  	g.genComment()
    21  	g.P("func (x *", g.typeName, ") Range(f func(", protoreflectPkg.Ident("FieldDescriptor"), ", ", protoreflectPkg.Ident("Value"), ") bool) {")
    22  	for _, field := range g.message.Fields {
    23  		g.genField(field)
    24  	}
    25  	g.P("}")
    26  }
    27  
    28  func (g *rangeGen) genComment() {
    29  	g.P("// Range iterates over every populated field in an undefined order,")
    30  	g.P("// calling f for each field descriptor and value encountered.")
    31  	g.P("// Range returns immediately if f returns false.")
    32  	g.P("// While iterating, mutating operations may only be performed")
    33  	g.P("// on the current field descriptor.")
    34  }
    35  
    36  func (g *rangeGen) genField(field *protogen.Field) {
    37  	if field.Oneof != nil {
    38  		g.genOneof(field)
    39  		return
    40  	}
    41  
    42  	switch {
    43  	case field.Desc.IsMap():
    44  		g.P("if len(x.", field.GoName, ") != 0 {")
    45  		g.P("value := ", protoreflectPkg.Ident("ValueOfMap"), "(&", mapTypeName(field), "{m: &x.", field.GoName, "})")
    46  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    47  		g.P("return")
    48  		g.P("}")
    49  		g.P("}")
    50  	case field.Desc.IsList():
    51  		g.P("if len(x.", field.GoName, ") != 0 {")
    52  		g.P("value := ", protoreflectPkg.Ident("ValueOfList"), "(&", listTypeName(field), "{list: &x.", field.GoName, "})")
    53  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    54  		g.P("return")
    55  		g.P("}")
    56  		g.P("}")
    57  	case field.Desc.Kind() == protoreflect.MessageKind:
    58  		g.P("if x.", field.GoName, " != nil {")
    59  		g.P("value := ", protoreflectPkg.Ident("ValueOfMessage"), "(x.", field.GoName, ".ProtoReflect())")
    60  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    61  		g.P("return")
    62  		g.P("}")
    63  		g.P("}")
    64  	case field.Desc.Kind() == protoreflect.BytesKind:
    65  		g.P("if len(x.", field.GoName, ") != 0 {")
    66  		g.P("value := ", protoreflectPkg.Ident("ValueOfBytes"), "(x.", field.GoName, ")")
    67  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    68  		g.P("return")
    69  		g.P("}")
    70  		g.P("}")
    71  	case field.Desc.Kind() == protoreflect.DoubleKind:
    72  		g.P("if x.", field.GoName, " != ", zeroValueForField(g.GeneratedFile, field), " || ", mathPkg.Ident("Signbit"), "(x.", field.GoName, ")", "{")
    73  		g.P("value := ", kindToValueConstructor(field.Desc.Kind()), "(x.", field.GoName, ")")
    74  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    75  		g.P("return")
    76  		g.P("}")
    77  		g.P("}")
    78  	case field.Desc.Kind() == protoreflect.FloatKind:
    79  		g.P("if x.", field.GoName, " != ", zeroValueForField(g.GeneratedFile, field), " || ", mathPkg.Ident("Signbit"), "(float64(x.", field.GoName, "))", "{")
    80  		g.P("value := ", kindToValueConstructor(field.Desc.Kind()), "(x.", field.GoName, ")")
    81  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    82  		g.P("return")
    83  		g.P("}")
    84  		g.P("}")
    85  	default:
    86  		g.P("if x.", field.GoName, " != ", zeroValueForField(g.GeneratedFile, field), "{")
    87  		switch {
    88  		case field.Desc.Kind() == protoreflect.EnumKind:
    89  			g.P("value := ", kindToValueConstructor(field.Desc.Kind()), "((", protoreflectPkg.Ident("EnumNumber"), ")(x.", field.GoName, ")) ")
    90  		default:
    91  			g.P("value := ", kindToValueConstructor(field.Desc.Kind()), "(x.", field.GoName, ")")
    92  		}
    93  		g.P("if !f(", fieldDescriptorName(field), ", value) {")
    94  		g.P("return")
    95  		g.P("}")
    96  		g.P("}")
    97  	}
    98  }
    99  
   100  func (g *rangeGen) genOneof(field *protogen.Field) {
   101  	// we check if it was processed or not
   102  	if _, ok := g.processedOneofs[field.Oneof.GoIdent.String()]; ok {
   103  		return
   104  	}
   105  	// we process it only if its != nil
   106  	g.P("if x.", field.Oneof.GoName, " != nil {")
   107  	g.P("switch o := x.", field.Oneof.GoName, ".(type) {")
   108  	for _, oneofField := range field.Oneof.Fields {
   109  		g.P("case *", g.QualifiedGoIdent(oneofField.GoIdent), ":")
   110  		g.P("v := ", "o.", oneofField.GoName)
   111  		switch oneofField.Desc.Kind() {
   112  		case protoreflect.MessageKind:
   113  			g.P("value := ", kindToValueConstructor(oneofField.Desc.Kind()), "(v.ProtoReflect())")
   114  		case protoreflect.EnumKind:
   115  			g.P("value :=", kindToValueConstructor(oneofField.Desc.Kind()), "((", protoreflectPkg.Ident("EnumNumber"), ")(v))")
   116  		default:
   117  			g.P("value := ", kindToValueConstructor(oneofField.Desc.Kind()), "(v)")
   118  
   119  		}
   120  		g.P("if !f(", fieldDescriptorName(oneofField), ", value) {")
   121  		g.P("return")
   122  		g.P("}")
   123  
   124  	}
   125  	g.P("}")
   126  	g.P("}")
   127  	// add this as processed oneof
   128  	g.processedOneofs[field.Oneof.GoIdent.String()] = struct{}{}
   129  }