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 }