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  }