github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/fastreflection/set.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 setGen struct {
    10  	*generator.GeneratedFile
    11  	typeName string
    12  	message  *protogen.Message
    13  }
    14  
    15  func (g *setGen) generate() {
    16  	g.genComment()
    17  	g.P("func (x *", g.typeName, ") Set(fd ", protoreflectPkg.Ident("FieldDescriptor"), ", value ", protoreflectPkg.Ident("Value"), ") {")
    18  	g.P("switch fd.FullName() {")
    19  	for _, field := range g.message.Fields {
    20  		g.P("case \"", field.Desc.FullName(), "\":")
    21  		g.genField(field)
    22  	}
    23  	g.P("default:")
    24  	g.genDefaultCase()
    25  	g.P("}")
    26  	g.P("}")
    27  	g.P()
    28  }
    29  
    30  func (g *setGen) genComment() {
    31  	g.P("// Set stores the value for a field.")
    32  	g.P("//")
    33  	g.P("// For a field belonging to a oneof, it implicitly clears any other field")
    34  	g.P("// that may be currently set within the same oneof.")
    35  	g.P("// For extension fields, it implicitly stores the provided ExtensionType.")
    36  	g.P("// When setting a composite type, it is unspecified whether the stored value")
    37  	g.P("// aliases the source's memory in any way. If the composite value is an")
    38  	g.P("// empty, read-only value, then it panics.")
    39  	g.P("//")
    40  	g.P("// Set is a mutating operation and unsafe for concurrent use.")
    41  }
    42  
    43  func (g *setGen) genField(field *protogen.Field) {
    44  	if field.Oneof != nil {
    45  		g.genOneof(field)
    46  		return
    47  	}
    48  
    49  	switch {
    50  	case field.Desc.IsMap():
    51  		g.genMap(field)
    52  		return
    53  	case field.Desc.IsList():
    54  		g.genList(field)
    55  		return
    56  	}
    57  
    58  	fieldRef := "x." + field.GoName
    59  
    60  	switch field.Desc.Kind() {
    61  	case protoreflect.BoolKind:
    62  		g.P(fieldRef, " = value.Bool()")
    63  	case protoreflect.EnumKind:
    64  		g.P(fieldRef, " = (", g.QualifiedGoIdent(field.Enum.GoIdent), ")(value.Enum())")
    65  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
    66  		g.P(fieldRef, " = int32(value.Int())")
    67  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
    68  		g.P(fieldRef, " = uint32(value.Uint())")
    69  	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
    70  		g.P(fieldRef, " = value.Int()")
    71  	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
    72  		g.P(fieldRef, " = value.Uint()")
    73  	case protoreflect.FloatKind:
    74  		g.P(fieldRef, " = float32(value.Float())")
    75  	case protoreflect.DoubleKind:
    76  		g.P(fieldRef, " = value.Float()")
    77  	case protoreflect.StringKind:
    78  		g.P(fieldRef, " = value.Interface().(string)")
    79  	case protoreflect.BytesKind:
    80  		g.P(fieldRef, " = value.Bytes()")
    81  	case protoreflect.MessageKind, protoreflect.GroupKind:
    82  		g.P(fieldRef, " = value.Message().Interface().(*", g.QualifiedGoIdent(field.Message.GoIdent), ")")
    83  	}
    84  
    85  }
    86  
    87  // genDefaultCase generates the default case for field descriptor
    88  func (g *setGen) genDefaultCase() {
    89  	g.P("if fd.IsExtension() {")
    90  	g.P("panic(", fmtPkg.Ident("Errorf"), "(\"proto3 declared messages do not support extensions: ", g.message.Desc.FullName(), "\"))")
    91  	g.P("}")
    92  	g.P("panic(fmt.Errorf(\"message ", g.message.Desc.FullName(), " does not contain field %s\", fd.FullName()))")
    93  }
    94  
    95  func (g *setGen) genOneof(field *protogen.Field) {
    96  	g.genOneofValueUnwrapper(field)
    97  	g.P("x.", field.Oneof.GoName, " = &", g.QualifiedGoIdent(field.GoIdent), "{", field.GoName, ": cv", "}")
    98  }
    99  
   100  // genMap generates the implementation of set for map types.
   101  // for implementation details look at genList
   102  func (g *setGen) genMap(field *protogen.Field) {
   103  	g.P("mv := value.Map()")
   104  	g.P("cmv := mv.(*", mapTypeName(field), ")")
   105  	g.P("x.", field.GoName, " = *cmv.m")
   106  }
   107  
   108  // genList generates the implementation of set for list types.
   109  // NOTE: in the original protoreflect implementation, using a List implementation
   110  // which does not match the expected impl.listReflect type panics.
   111  // To respect this behaviour, we use the fastpath list casting to our
   112  // list implementation. This is to respect mutability guarantees.
   113  // After we set a list the value can still be mutated.
   114  func (g *setGen) genList(field *protogen.Field) {
   115  	g.P("lv := value.List()")
   116  	g.P("clv := lv.(*", listTypeName(field), ")")
   117  	g.P("x.", field.GoName, " = *clv.list")
   118  }
   119  
   120  func (g *setGen) genOneofValueUnwrapper(field *protogen.Field) {
   121  	fieldRef := "cv  := "
   122  	switch field.Desc.Kind() {
   123  	case protoreflect.BoolKind:
   124  		g.P(fieldRef, " value.Bool()")
   125  	case protoreflect.EnumKind:
   126  		g.P(fieldRef, " (", g.QualifiedGoIdent(field.Enum.GoIdent), ")(value.Enum())")
   127  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
   128  		g.P(fieldRef, " int32(value.Int())")
   129  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
   130  		g.P(fieldRef, " uint32(value.Uint())")
   131  	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
   132  		g.P(fieldRef, "  value.Int()")
   133  	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
   134  		g.P(fieldRef, "  value.Uint()")
   135  	case protoreflect.FloatKind:
   136  		g.P(fieldRef, "  float32(value.Float())")
   137  	case protoreflect.DoubleKind:
   138  		g.P(fieldRef, "  value.Float()")
   139  	case protoreflect.StringKind:
   140  		g.P(fieldRef, "  value.Interface().(string)")
   141  	case protoreflect.BytesKind:
   142  		g.P(fieldRef, "  value.Bytes()")
   143  	case protoreflect.MessageKind, protoreflect.GroupKind:
   144  		g.P(fieldRef, "  value.Message().Interface().(*", g.QualifiedGoIdent(field.Message.GoIdent), ")")
   145  	}
   146  }