frostfs-api-go/util/protogen/internalgengo/proto_stable_compat.go
Evgenii Stratonikov adb7c602d7 [#77] protogen: Initial implementation
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2024-08-19 10:47:00 +03:00

124 lines
4.4 KiB
Go

package internalgengo
import (
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/reflect/protoreflect"
)
var protowirePackage = protogen.GoImportPath("google.golang.org/protobuf/encoding/protowire")
func emitStableSize(g *protogen.GeneratedFile, msg *protogen.Message) {
fs := sortFields(msg.Fields)
g.P("// StableSize returns the size of x in protobuf format.")
g.P("//")
g.P("// Structures with the same field values have the same binary size.")
g.P("func (x *", msg.GoIdent.GoName, ") StableSize() (size int) {")
g.P("if x == nil { return 0 }")
if len(fs) != 0 {
for _, f := range fs {
if f.Desc.IsList() && marshalers[f.Desc.Kind()].RepeatedDouble && !(f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()) {
g.P("var n int")
break
}
}
for _, f := range fs {
emitFieldSize(g, f)
}
}
g.P("return size")
g.P("}\n")
}
func emitSignatureMethods(g *protogen.GeneratedFile, msg *protogen.Message) {
// SignedDataSize implementation (only for requests and responses).
g.P("// ReadSignedData fills buf with signed data of x.")
g.P("// If buffer length is less than x.SignedDataSize(), new buffer is allocated.")
g.P("//")
g.P("// Returns any error encountered which did not allow writing the data completely.")
g.P("// Otherwise, returns the buffer in which the data is written.")
g.P("//")
g.P("// Structures with the same field values have the same signed data.")
g.P("func (x *", msg.GoIdent.GoName, ") SignedDataSize() int {")
g.P("return x.GetBody().StableSize()")
g.P("}\n")
// ReadSignedData implementation (only for requests and responses).
g.P("// SignedDataSize returns size of the request signed data in bytes.")
g.P("//")
g.P("// Structures with the same field values have the same signed data size.")
g.P("func (x *", msg.GoIdent.GoName, ") ReadSignedData(buf []byte) ([]byte, error) {")
g.P("return x.GetBody().MarshalProtobuf(buf), nil")
g.P("}\n")
}
func emitFieldSize(g *protogen.GeneratedFile, f *protogen.Field) {
m := marshalers[f.Desc.Kind()]
if m.Prefix == "" {
g.P("// FIXME missing field marshaler: ", f.GoName, " of type ", f.Desc.Kind().String())
g.P(`panic("unimplemented")`)
return
}
name := castFieldName(f)
if f.Oneof != nil {
name = "x." + f.Oneof.GoName
g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {")
defer g.P("}")
name = "inner." + f.GoName
}
switch {
case f.Desc.IsList() && (f.Desc.Kind() == protoreflect.MessageKind || f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()):
g.P("for i := range ", name, "{")
if f.Desc.Kind() == protoreflect.MessageKind {
g.P("size += ", protoPackage.Ident("NestedStructureSize"), "(", f.Desc.Number(), ", ", name, "[i])")
} else {
if f.Desc.Kind() != protoreflect.Uint64Kind {
panic("only uint64 unpacked primitive is supported")
}
g.P("size += ", protowirePackage.Ident("SizeGroup"), "(",
protowirePackage.Ident("Number"), "(", f.Desc.Number(), "), ",
protowirePackage.Ident("SizeVarint"), "(", name, "[i]))")
}
g.P("}")
case f.Desc.IsList():
if m.RepeatedDouble {
g.P("n, _ = ", protoPackage.Ident("Repeated"+m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")")
g.P("size += n")
} else {
g.P("size += ", protoPackage.Ident("Repeated"+m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")")
}
default:
g.P("size += ", protoPackage.Ident(m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")")
}
}
type marshalerDesc struct {
Prefix string
RepeatedDouble bool
}
// Unused kinds are commented.
var marshalers = map[protoreflect.Kind]marshalerDesc{
protoreflect.BoolKind: {Prefix: "Bool"},
protoreflect.EnumKind: {Prefix: "Enum"},
protoreflect.Int32Kind: {Prefix: "Int32", RepeatedDouble: true},
// protoreflect.Sint32Kind: "",
protoreflect.Uint32Kind: {Prefix: "UInt32", RepeatedDouble: true},
protoreflect.Int64Kind: {Prefix: "Int64", RepeatedDouble: true},
// protoreflect.Sint64Kind: "",
protoreflect.Uint64Kind: {Prefix: "UInt64", RepeatedDouble: true},
// protoreflect.Sfixed32Kind: "",
protoreflect.Fixed32Kind: {Prefix: "Fixed32", RepeatedDouble: true},
// protoreflect.FloatKind: "",
// protoreflect.Sfixed64Kind: "",
protoreflect.Fixed64Kind: {Prefix: "Fixed64", RepeatedDouble: true},
protoreflect.DoubleKind: {Prefix: "Float64"},
protoreflect.StringKind: {Prefix: "String"},
protoreflect.BytesKind: {Prefix: "Bytes"},
protoreflect.MessageKind: {Prefix: "NestedStructure"},
// protoreflect.GroupKind: "",
}