github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/fastreflection/proto_message.go (about)

     1  package fastreflection
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/cosmos/cosmos-proto/features/fastreflection/copied"
     6  	"github.com/cosmos/cosmos-proto/generator"
     7  	"google.golang.org/protobuf/compiler/protogen"
     8  )
     9  
    10  const (
    11  	protoreflectPkg = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect")
    12  	protoifacePkg   = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoiface")
    13  	protoimplPkg    = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl")
    14  	protoPkg        = protogen.GoImportPath("google.golang.org/protobuf/proto")
    15  
    16  	sortPkg     = protogen.GoImportPath("sort")
    17  	fmtPkg      = protogen.GoImportPath("fmt")
    18  	mathPackage = protogen.GoImportPath("math")
    19  
    20  	runtimePackage = protogen.GoImportPath("github.com/cosmos/cosmos-proto/runtime")
    21  )
    22  
    23  func GenProtoMessage(f *protogen.File, g *generator.GeneratedFile, message *protogen.Message) {
    24  	genMessage(f, g, message)
    25  	// check for message declarations within a message declaration
    26  	for _, nested := range message.Messages {
    27  		// map entries are defines as messages, but we don't want to generate those.
    28  		if nested.Desc.IsMapEntry() {
    29  			continue
    30  		}
    31  		GenProtoMessage(f, g, nested)
    32  	}
    33  }
    34  
    35  func genMessage(f *protogen.File, g *generator.GeneratedFile, message *protogen.Message) {
    36  	gen := newGenerator(f, g, message)
    37  	gen.generateExtraTypes()
    38  	gen.generateReflectionType()
    39  	gen.genMessageType()
    40  	gen.genDescriptor()
    41  	gen.genType()
    42  	gen.genNew()
    43  	gen.genInterface()
    44  	gen.genRange()
    45  	gen.genHas()
    46  	gen.genClear()
    47  	gen.genGet()
    48  	gen.genSet()
    49  	gen.gentMutable()
    50  	gen.genNewField()
    51  	gen.genWhichOneof()
    52  	gen.genGetUnknown()
    53  	gen.genSetUnknown()
    54  	gen.genIsValid()
    55  	gen.genProtoMethods()
    56  }
    57  
    58  func fastReflectionTypeName(message *protogen.Message) string {
    59  	return fmt.Sprintf("fastReflection_%s", message.GoIdent.GoName)
    60  }
    61  
    62  // generateExtraTypes generates the protoreflect.List and protoreflect.Map types required.
    63  func (g *fastGenerator) generateExtraTypes() {
    64  	for _, field := range g.message.Fields {
    65  		switch {
    66  		case field.Desc.IsMap():
    67  			g.generateMapType(field)
    68  		case field.Desc.IsList():
    69  			g.generateListType(field)
    70  		}
    71  	}
    72  
    73  	// generate descriptors
    74  	(&descGen{
    75  		GeneratedFile: g.GeneratedFile,
    76  		file:          g.file,
    77  		message:       g.message,
    78  	}).generate()
    79  }
    80  
    81  // generateMapType generates the fastReflectionFeature reflection protoreflect.Map type
    82  // related to the provided protogen.Field.
    83  func (g *fastGenerator) generateMapType(field *protogen.Field) {
    84  	(&mapGen{
    85  		GeneratedFile: g.GeneratedFile,
    86  		field:         field,
    87  	}).generate()
    88  }
    89  
    90  // generateListType generates the fastReflectionFeature reflection protoreflect.List type
    91  // related to the provided protogen.Field.
    92  func (g *fastGenerator) generateListType(field *protogen.Field) {
    93  	(&listGen{
    94  		GeneratedFile: g.GeneratedFile,
    95  		field:         field,
    96  	}).generate()
    97  }
    98  
    99  func (g *fastGenerator) genMessageType() {
   100  	(&messageTypeGen{
   101  		typeName:        g.typeName,
   102  		GeneratedFile:   g.GeneratedFile,
   103  		message:         g.message,
   104  		file:            g.file,
   105  		messageTypeName: "",
   106  	}).generate()
   107  }
   108  
   109  func (g *fastGenerator) generateReflectionType() {
   110  	// gen interface assertion
   111  	g.P("var _ ", protoreflectPkg.Ident("Message"), " = (*", g.typeName, ")(nil)")
   112  	g.P()
   113  	// gen type
   114  	g.P("type ", g.typeName, " ", g.message.GoIdent.GoName)
   115  	// gen msg implementation
   116  	g.P("func (x *", g.message.GoIdent.GoName, ") ProtoReflect() ", protoreflectPkg.Ident("Message"), "{")
   117  	g.P("return (*", g.typeName, ")(x)")
   118  	g.P("}")
   119  	g.P()
   120  
   121  	// gen slowreflection
   122  	f := copied.NewFileInfo(g.file)
   123  	idx := func() int {
   124  		var id int
   125  		var found bool
   126  		for mInfo, index := range f.AllMessagesByPtr {
   127  			if mInfo.Message.Desc.FullName() == g.message.Desc.FullName() {
   128  				id = index
   129  				found = true
   130  			}
   131  		}
   132  		if !found {
   133  			panic("not found")
   134  		}
   135  		return id
   136  	}()
   137  	typesVar := copied.MessageTypesVarName(f)
   138  
   139  	// ProtoReflect method.
   140  	g.P("func (x *", g.message.GoIdent, ") slowProtoReflect() ", protoreflectPkg.Ident("Message"), " {")
   141  	g.P("mi := &", typesVar, "[", idx, "]")
   142  	g.P("if ", protoimplPkg.Ident("UnsafeEnabled"), " && x != nil {")
   143  	g.P("ms := ", protoimplPkg.Ident("X"), ".MessageStateOf(", protoimplPkg.Ident("Pointer"), "(x))")
   144  	g.P("if ms.LoadMessageInfo() == nil {")
   145  	g.P("ms.StoreMessageInfo(mi)")
   146  	g.P("}")
   147  	g.P("return ms")
   148  	g.P("}")
   149  	g.P("return mi.MessageOf(x)")
   150  	g.P("}")
   151  	g.P()
   152  }
   153  
   154  func (g *fastGenerator) genDescriptor() {
   155  	g.P("// Descriptor returns message descriptor, which contains only the protobuf")
   156  	g.P("// type information for the message.")
   157  	g.P("func (x *", g.typeName, ") Descriptor() ", protoreflectPkg.Ident("MessageDescriptor"), " {")
   158  	g.P("return ", messageDescriptorName(g.message))
   159  	g.P("}")
   160  	g.P()
   161  }
   162  
   163  func (g *fastGenerator) genType() {
   164  	g.P("// Type returns the message type, which encapsulates both Go and protobuf")
   165  	g.P("// type information. If the Go type information is not needed,")
   166  	g.P("// it is recommended that the message descriptor be used instead.")
   167  	g.P("func (x *", g.typeName, ") Type() ", protoreflectPkg.Ident("MessageType"), " {")
   168  	g.P("return ", messageTypeNameVar(g.message))
   169  	g.P("}")
   170  	g.P()
   171  }
   172  
   173  func (g *fastGenerator) genNew() {
   174  	g.P("// New returns a newly allocated and mutable empty message.")
   175  	g.P("func (x *", g.typeName, ") New() ", protoreflectPkg.Ident("Message"), " {")
   176  	g.P("return new(", g.typeName, ")")
   177  	g.P("}")
   178  	g.P()
   179  }
   180  
   181  func (g *fastGenerator) genInterface() {
   182  	g.P("// Interface unwraps the message reflection interface and")
   183  	g.P("// returns the underlying ProtoMessage interface.")
   184  	g.P("func (x *", g.typeName, ") Interface() ", protoreflectPkg.Ident("ProtoMessage"), " {")
   185  	g.P("return (*", g.message.GoIdent, ")(x)")
   186  	g.P("}")
   187  	g.P()
   188  }
   189  
   190  func (g *fastGenerator) genRange() {
   191  	(&rangeGen{
   192  		GeneratedFile: g.GeneratedFile,
   193  		typeName:      g.typeName,
   194  		message:       g.message,
   195  	}).generate()
   196  	g.P()
   197  }
   198  
   199  func (g *fastGenerator) genHas() {
   200  	(&hasGen{
   201  		GeneratedFile: g.GeneratedFile,
   202  		typeName:      g.typeName,
   203  		message:       g.message,
   204  	}).generate()
   205  }
   206  
   207  func (g *fastGenerator) genClear() {
   208  	(&clearGen{
   209  		GeneratedFile: g.GeneratedFile,
   210  		typeName:      g.typeName,
   211  		message:       g.message,
   212  	}).generate()
   213  
   214  	g.P()
   215  }
   216  
   217  func (g *fastGenerator) genSet() {
   218  	(&setGen{
   219  		GeneratedFile: g.GeneratedFile,
   220  		typeName:      g.typeName,
   221  		message:       g.message,
   222  	}).generate()
   223  }
   224  
   225  func (g *fastGenerator) gentMutable() {
   226  	(&mutableGen{
   227  		GeneratedFile: g.GeneratedFile,
   228  		typeName:      g.typeName,
   229  		message:       g.message,
   230  	}).generate()
   231  }
   232  
   233  func (g *fastGenerator) genNewField() {
   234  	(&newFieldGen{
   235  		GeneratedFile: g.GeneratedFile,
   236  		typeName:      g.typeName,
   237  		message:       g.message,
   238  	}).generate()
   239  	g.P()
   240  }
   241  
   242  func (g *fastGenerator) genWhichOneof() {
   243  	(&whichOneofGen{
   244  		GeneratedFile: g.GeneratedFile,
   245  		typeName:      g.typeName,
   246  		message:       g.message,
   247  	}).generate()
   248  }
   249  
   250  func (g *fastGenerator) genGetUnknown() {
   251  	g.P("// GetUnknown retrieves the entire list of unknown fields.")
   252  	g.P("// The caller may only mutate the contents of the RawFields")
   253  	g.P("// if the mutated bytes are stored back into the message with SetUnknown.")
   254  	g.P("func (x *", g.typeName, ") GetUnknown() ", protoreflectPkg.Ident("RawFields"), " {")
   255  	g.P("return x.unknownFields")
   256  	g.P("}")
   257  	g.P()
   258  }
   259  
   260  func (g *fastGenerator) genSetUnknown() {
   261  	g.P("// SetUnknown stores an entire list of unknown fields.")
   262  	g.P("// The raw fields must be syntactically valid according to the wire format.")
   263  	g.P("// An implementation may panic if this is not the case.")
   264  	g.P("// Once stored, the caller must not mutate the content of the RawFields.")
   265  	g.P("// An empty RawFields may be passed to clear the fields.")
   266  	g.P("//")
   267  	g.P("// SetUnknown is a mutating operation and unsafe for concurrent use.")
   268  	g.P("func (x *", g.typeName, ") SetUnknown(fields ", protoreflectPkg.Ident("RawFields"), ") {")
   269  	g.P("x.unknownFields = fields")
   270  	g.P("}")
   271  	g.P()
   272  }
   273  
   274  func (g *fastGenerator) genIsValid() {
   275  	g.P("// IsValid reports whether the message is valid.")
   276  	g.P("//")
   277  	g.P("// An invalid message is an empty, read-only value.")
   278  	g.P("//")
   279  	g.P("// An invalid message often corresponds to a nil pointer of the concrete")
   280  	g.P("// message type, but the details are implementation dependent.")
   281  	g.P("// Validity is not part of the protobuf data model, and may not")
   282  	g.P("// be preserved in marshaling or other operations.")
   283  
   284  	g.P("func (x *", g.typeName, ") IsValid() bool {")
   285  	g.P("return x != nil")
   286  	g.P("}")
   287  	g.P()
   288  }
   289  
   290  func (g *fastGenerator) genProtoMethods() {
   291  	g.P("// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations.")
   292  	g.P("// This method may return nil.")
   293  	g.P("//")
   294  	g.P("// The returned methods type is identical to")
   295  	g.P(`// "google.golang.org/protobuf/runtime/protoiface".Methods.`)
   296  	g.P("// Consult the protoiface package documentation for details.")
   297  	g.P("func (x *", g.typeName, ") ProtoMethods() *", protoifacePkg.Ident("Methods"), " {")
   298  
   299  	g.genSizeMethod()
   300  	g.genMarshalMethod()
   301  	g.genUnmarshalMethod()
   302  
   303  	g.P("return &", protoifacePkg.Ident("Methods"), "{ ")
   304  	g.P("NoUnkeyedLiterals: struct{}{},")
   305  	g.P("Flags: ", protoifacePkg.Ident("SupportMarshalDeterministic"), "|", protoifacePkg.Ident("SupportUnmarshalDiscardUnknown"), ",")
   306  	g.P("Size: size,")
   307  	g.P("Marshal: marshal,")
   308  	g.P("Unmarshal: unmarshal,")
   309  	g.P("Merge: nil,")
   310  	g.P("CheckInitialized: nil,")
   311  	g.P("}")
   312  	g.P("}")
   313  }