github.com/TrueCloudLab/frostfs-api-go/v2@v2.0.0-20230228134343-196241c4e79a/util/protogen/main.go (about) 1 package main 2 3 import ( 4 "sort" 5 "strings" 6 7 "google.golang.org/protobuf/compiler/protogen" 8 "google.golang.org/protobuf/reflect/protoreflect" 9 ) 10 11 func main() { 12 protogen.Options{}.Run(func(gen *protogen.Plugin) error { 13 for _, f := range gen.Files { 14 //if !f.Generate { 15 // continue 16 //} 17 imp := string(f.GoImportPath) 18 if strings.HasSuffix(imp, "/tree") || strings.HasSuffix(imp, "/control") { 19 generateFile(gen, f) 20 } 21 } 22 return nil 23 }) 24 } 25 26 // generateFile generates a *.pb.go file enforcing field-order serialization. 27 func generateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { 28 filename := file.GeneratedFilenamePrefix + "_frostfs.pb.go" 29 g := gen.NewGeneratedFile(filename, file.GoImportPath) 30 g.P("// Code generated by protoc-gen-go-frostfs. DO NOT EDIT.") 31 g.P() 32 g.P("package ", file.GoPackageName) 33 g.P() 34 g.P(`import "github.com/TrueCloudLab/frostfs-api-go/v2/util/proto"`) 35 36 //for _, e := range file.Enums { 37 // g.P("type " + e.GoIdent.GoName + " int32") 38 // g.P("const (") 39 // for _, ev := range e.Values { 40 // g.P(ev.GoIdent.GoName, " = ", ev.Desc.Number()) 41 // } 42 // g.P(")") 43 //} 44 for _, msg := range file.Messages { 45 emitMessage(g, msg) 46 } 47 return g 48 } 49 50 func emitMessage(g *protogen.GeneratedFile, msg *protogen.Message) { 51 for _, inner := range msg.Messages { 52 emitMessage(g, inner) 53 } 54 55 fs := sortFields(msg.Fields) 56 57 // StableSize implementation. 58 g.P("// StableSize returns the size of x in protobuf format.") 59 g.P("//") 60 g.P("// Structures with the same field values have the same binary size.") 61 g.P("func (x *", msg.GoIdent.GoName, ") StableSize() (size int) {") 62 if len(fs) != 0 { 63 for _, f := range fs { 64 if f.Desc.IsList() && marshalers[f.Desc.Kind()].RepeatedDouble { 65 g.P("var n int") 66 break 67 } 68 } 69 for _, f := range fs { 70 emitFieldSize(g, f) 71 } 72 } 73 g.P("return size") 74 g.P("}\n") 75 76 // StableMarshal implementation. 77 g.P("// StableMarshal marshals x in protobuf binary format with stable field order.") 78 g.P("//") 79 g.P("// If buffer length is less than x.StableSize(), new buffer is allocated.") 80 g.P("//") 81 g.P("// Returns any error encountered which did not allow writing the data completely.") 82 g.P("// Otherwise, returns the buffer in which the data is written.") 83 g.P("//") 84 g.P("// Structures with the same field values have the same binary format.") 85 g.P("func (x *", msg.GoIdent.GoName, ") StableMarshal(buf []byte) []byte {") 86 if len(fs) != 0 { 87 g.P("if x == nil { return []byte{} }") 88 g.P("if buf == nil { buf = make([]byte, x.StableSize()) }") 89 g.P("var offset int") 90 for _, f := range fs { 91 emitFieldMarshal(g, f) 92 } 93 } 94 g.P("return buf") 95 g.P("}\n") 96 97 if strings.HasSuffix(msg.GoIdent.GoName, "Request") || strings.HasSuffix(msg.GoIdent.GoName, "Response") { 98 // SignedDataSize implementation (only for requests and responses). 99 g.P("// ReadSignedData fills buf with signed data of x.") 100 g.P("// If buffer length is less than x.SignedDataSize(), new buffer is allocated.") 101 g.P("//") 102 g.P("// Returns any error encountered which did not allow writing the data completely.") 103 g.P("// Otherwise, returns the buffer in which the data is written.") 104 g.P("//") 105 g.P("// Structures with the same field values have the same signed data.") 106 g.P("func (x *", msg.GoIdent.GoName, ") SignedDataSize() int {") 107 g.P("return x.GetBody().StableSize()") 108 g.P("}\n") 109 110 // ReadSignedData implementation (only for requests and responses). 111 g.P("// SignedDataSize returns size of the request signed data in bytes.") 112 g.P("//") 113 g.P("// Structures with the same field values have the same signed data size.") 114 g.P("func (x *", msg.GoIdent.GoName, ") ReadSignedData(buf []byte) ([]byte, error) {") 115 g.P("return x.GetBody().StableMarshal(buf), nil") 116 g.P("}\n") 117 118 // Signature setters and getters. 119 g.P("func (x *", msg.GoIdent.GoName, ") SetSignature(sig *Signature) {") 120 g.P("x.Signature = sig") 121 g.P("}\n") 122 } 123 } 124 125 func emitFieldSize(g *protogen.GeneratedFile, f *protogen.Field) { 126 m := marshalers[f.Desc.Kind()] 127 if m.Prefix == "" { 128 g.P("// FIXME missing field marshaler: ", f.GoName, " of type ", f.Desc.Kind().String()) 129 g.P(`panic("unimplemented")`) 130 return 131 } 132 133 name := castFieldName(f) 134 if f.Oneof != nil { 135 name = "x." + f.Oneof.GoName 136 g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {") 137 defer g.P("}") 138 name = "inner." + f.GoName 139 } 140 141 switch { 142 case f.Desc.IsList() && f.Desc.Kind() == protoreflect.MessageKind: 143 g.P("for i := range ", name, "{") 144 g.P("size += proto.NestedStructureSize(", f.Desc.Number(), ", ", name, "[i])") 145 g.P("}") 146 case f.Desc.IsList(): 147 if m.RepeatedDouble { 148 g.P("n, _ = proto.Repeated", m.Prefix, "Size(", f.Desc.Number(), ", ", name, ")") 149 g.P("size += n") 150 } else { 151 g.P("size += proto.Repeated", m.Prefix, "Size(", f.Desc.Number(), ", ", name, ")") 152 } 153 default: 154 g.P("size += proto.", m.Prefix, "Size(", f.Desc.Number(), ", ", name, ")") 155 } 156 } 157 158 func emitFieldMarshal(g *protogen.GeneratedFile, f *protogen.Field) { 159 m := marshalers[f.Desc.Kind()] 160 if m.Prefix == "" { 161 g.P("// FIXME missing field marshaler: ", f.GoName, " of type ", f.Desc.Kind().String()) 162 g.P(`panic("unimplemented")`) 163 return 164 } 165 166 name := castFieldName(f) 167 if f.Oneof != nil { 168 name = "x." + f.Oneof.GoName 169 g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {") 170 defer g.P("}") 171 name = "inner." + f.GoName 172 } 173 174 prefix := m.Prefix 175 if f.Desc.IsList() { 176 prefix = "Repeated" + m.Prefix 177 } 178 switch { 179 case f.Desc.IsList() && f.Desc.Kind() == protoreflect.MessageKind: 180 g.P("for i := range ", name, "{") 181 g.P("offset += proto.NestedStructureMarshal(", f.Desc.Number(), ", buf[offset:], ", name, "[i])") 182 g.P("}") 183 case f.Desc.IsList(): 184 g.P("offset += proto.Repeated", m.Prefix, "Marshal(", f.Desc.Number(), ", buf[offset:], ", name, ")") 185 default: 186 g.P("offset += proto.", prefix, "Marshal(", f.Desc.Number(), ", buf[offset:], ", name, ")") 187 } 188 } 189 190 func castFieldName(f *protogen.Field) string { 191 name := "x." + f.GoName 192 if f.Desc.Kind() != protoreflect.EnumKind { 193 return name 194 } 195 return "int32(" + name + ")" 196 } 197 198 type marshalerDesc struct { 199 Prefix string 200 RepeatedDouble bool 201 } 202 203 // Unused kinds are commented. 204 var marshalers = map[protoreflect.Kind]marshalerDesc{ 205 protoreflect.BoolKind: {Prefix: "Bool"}, 206 protoreflect.EnumKind: {Prefix: "Enum"}, 207 //protoreflect.Int32Kind: "", 208 //protoreflect.Sint32Kind: "", 209 protoreflect.Uint32Kind: {Prefix: "UInt32", RepeatedDouble: true}, 210 protoreflect.Int64Kind: {Prefix: "Int64", RepeatedDouble: true}, 211 //protoreflect.Sint64Kind: "", 212 protoreflect.Uint64Kind: {Prefix: "UInt64", RepeatedDouble: true}, 213 //protoreflect.Sfixed32Kind: "", 214 protoreflect.Fixed32Kind: {Prefix: "Fixed32", RepeatedDouble: true}, 215 //protoreflect.FloatKind: "", 216 //protoreflect.Sfixed64Kind: "", 217 protoreflect.Fixed64Kind: {Prefix: "Fixed64", RepeatedDouble: true}, 218 protoreflect.DoubleKind: {Prefix: "Float64"}, 219 protoreflect.StringKind: {Prefix: "String"}, 220 protoreflect.BytesKind: {Prefix: "Bytes"}, 221 protoreflect.MessageKind: {Prefix: "NestedStructure"}, 222 //protoreflect.GroupKind: "", 223 } 224 225 func sortFields(fs []*protogen.Field) []*protogen.Field { 226 res := make([]*protogen.Field, len(fs)) 227 copy(res, fs) 228 sort.Slice(res, func(i, j int) bool { 229 return res[i].Desc.Number() < res[j].Desc.Number() 230 }) 231 return res 232 }