frostfs-api-go/util/protogen/internalgengo/proto.go

203 lines
5.7 KiB
Go
Raw Permalink Normal View History

package internalgengo
import (
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/reflect/protoreflect"
)
func emitProtoMethods(g *protogen.GeneratedFile, msg *protogen.Message) {
emitMarshalProtobuf(g, msg)
emitUnmarshalProtobuf(g, msg)
}
func emitUnmarshalProtobuf(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("// UnmarshalProtobuf implements the encoding.ProtoUnmarshaler interface.")
g.P("func (x *", msg.GoIdent.GoName, ") UnmarshalProtobuf(src []byte) (err error) {")
g.P("var fc ", easyprotoPackage.Ident("FieldContext"))
g.P("for len(src) > 0 {")
{
g.P("src, err = fc.NextField(src)")
g.P("if err != nil { return ", fmtPackage.Ident("Errorf"), `("cannot read next field in %s", "`, msg.GoIdent.GoName, `")}`)
g.P("switch fc.FieldNum {")
{
for _, f := range msg.Fields {
g.P("case ", f.Desc.Number(), ":", " // ", f.GoName)
emitFieldUnmarshal(g, f)
}
}
g.P("}")
}
g.P("}")
g.P("return nil")
g.P("}")
}
func emitFieldUnmarshal(g *protogen.GeneratedFile, f *protogen.Field) {
name := castFieldName(f)
if f.Desc.Kind() == protoreflect.MessageKind {
g.P("data, ok := fc.MessageData()")
g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`)
if f.Desc.IsList() {
[#111] protogen: Emit slice of messages without a pointer ``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ old │ new │ │ sec/op │ sec/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 3.193n ± 2% 3.242n ± 0% +1.50% (p=0.034 n=10) ObjectIDSlice/0_elements/from_grpc_message-8 3.197n ± 2% 3.343n ± 1% +4.57% (p=0.000 n=10) ObjectIDSlice/0_elements/marshal-8 5.666n ± 3% 5.642n ± 0% -0.42% (p=0.000 n=10) ObjectIDSlice/1_elements/to_grpc_message-8 53.10n ± 6% 29.78n ± 12% -43.92% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 28.99n ± 5% 29.77n ± 7% ~ (p=0.165 n=10) ObjectIDSlice/1_elements/marshal-8 49.08n ± 7% 50.72n ± 6% ~ (p=0.218 n=10) ObjectIDSlice/50_elements/to_grpc_message-8 1652.5n ± 7% 277.2n ± 1% -83.22% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 261.2n ± 11% 226.7n ± 15% -13.19% (p=0.003 n=10) ObjectIDSlice/50_elements/marshal-8 1.512µ ± 6% 1.514µ ± 6% ~ (p=0.955 n=10) geomean 52.15n 39.99n -23.31% │ old │ new │ │ B/op │ B/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/from_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/marshal-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/to_grpc_message-8 32.00 ± 0% 24.00 ± 0% -25.00% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 24.00 ± 0% 24.00 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/marshal-8 48.00 ± 0% 48.00 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/to_grpc_message-8 1.578Ki ± 0% 1.250Ki ± 0% -20.79% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 1.250Ki ± 0% 1.250Ki ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/marshal-8 2.000Ki ± 0% 2.000Ki ± 0% ~ (p=1.000 n=10) ¹ geomean ² -5.62% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ old │ new │ │ allocs/op │ allocs/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/from_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/marshal-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/to_grpc_message-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/marshal-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/to_grpc_message-8 51.000 ± 0% 1.000 ± 0% -98.04% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/marshal-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² -40.18% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ``` Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2024-08-27 12:12:31 +00:00
g.P(name, " = append(", name, ", ", fieldType(g, f)[2:], "{})")
g.P("ff := &", name, "[len(", name, ")-1]")
name = "ff"
} else if f.Oneof != nil {
const tmp = "oneofField"
g.P(tmp, " := &", f.GoIdent, "{", f.GoName, ": ", "new(", fieldType(g, f)[1:], ")}")
defer g.P(name, " = ", tmp)
name = tmp + "." + f.GoName
} else {
g.P(name, " = new(", fieldType(g, f)[1:], ")")
}
g.P(`if err := `, name, `.UnmarshalProtobuf(data); err != nil { return fmt.Errorf("unmarshal: %w", err)}`)
return
}
getter, _ := easyprotoKindInfo(f.Desc.Kind())
if f.Desc.IsList() && (f.Desc.Kind() == protoreflect.BytesKind || f.Desc.Kind() == protoreflect.StringKind || f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()) {
g.P("data, ok := fc.", getter, "()")
g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`)
g.P(name, " = append(", name, ", data)")
return
}
if f.Desc.IsList() {
g.P("data, ok := fc.Unpack", getter, "s(nil)")
} else {
g.P("data, ok := fc.", getter, "()")
}
g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`)
value := "data"
if f.Desc.Kind() == protoreflect.EnumKind {
value = fieldType(g, f).String() + "(data)"
}
if f.Oneof == nil {
g.P("x.", f.GoName, " = ", value)
} else {
g.P("x.", f.Oneof.GoName, " = &", f.GoIdent, "{", f.GoName, ": data}")
}
}
func emitMarshalProtobuf(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("// MarshalProtobuf implements the encoding.ProtoMarshaler interface.")
g.P("func (x *", msg.GoIdent.GoName, ") MarshalProtobuf(dst []byte) []byte {")
g.P("m := ", mp, ".Get()")
g.P("defer ", mp, ".Put(m)")
g.P("x.EmitProtobuf(m.MessageMarshaler())")
g.P("dst = m.Marshal(dst)")
g.P("return dst")
g.P("}\n")
g.P("func (x *", msg.GoIdent.GoName, ") EmitProtobuf(mm *", easyprotoPackage.Ident("MessageMarshaler"), ") {")
if len(msg.Fields) != 0 {
fs := sortFields(msg.Fields)
g.P("if x == nil { return }")
for _, f := range fs {
emitFieldMarshal(g, f)
}
}
g.P("}")
}
func emitMarshalOneof(g *protogen.GeneratedFile, f *protogen.Field) {
name := "x." + f.Oneof.GoName
g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {")
defer g.P("}")
emitMarshalRaw(g, f, "inner."+f.GoName)
}
// easyprotoKindInfo returns string name for kind, used in easyproto methods.
// The second return value is a condition to test for the default value of kind.
func easyprotoKindInfo(kind protoreflect.Kind) (string, func(string) string) {
switch kind {
case protoreflect.BoolKind:
return "Bool", identity
case protoreflect.EnumKind:
return "Int32", notZero
case protoreflect.Int32Kind:
return "Int32", notZero
case protoreflect.Sint32Kind:
return "Sint32", notZero
case protoreflect.Uint32Kind:
return "Uint32", notZero
case protoreflect.Int64Kind:
return "Int64", notZero
case protoreflect.Sint64Kind:
return "Sint64", notZero
case protoreflect.Uint64Kind:
return "Uint64", notZero
case protoreflect.Sfixed32Kind:
return "Sfixed32", notZero
case protoreflect.Fixed32Kind:
return "Fixed32", notZero
case protoreflect.FloatKind:
return "Float", notZero
case protoreflect.Sfixed64Kind:
return "Sfixed64", notZero
case protoreflect.Fixed64Kind:
return "Fixed64", notZero
case protoreflect.DoubleKind:
return "Double", notZero
case protoreflect.StringKind:
return "String", notEmpty
case protoreflect.BytesKind:
return "Bytes", notEmpty
case protoreflect.GroupKind:
panic("unimplemented")
default:
panic("unreachable")
}
}
func emitFieldMarshal(g *protogen.GeneratedFile, f *protogen.Field) {
if f.Oneof != nil {
emitMarshalOneof(g, f)
return
}
emitMarshalRaw(g, f, castFieldName(f))
}
func emitMarshalRaw(g *protogen.GeneratedFile, f *protogen.Field, name string) {
if f.Desc.Kind() == protoreflect.MessageKind {
if f.Desc.IsList() {
g.P("for i := range ", name, " {")
defer g.P("}")
name += "[i]"
[#111] protogen: Emit slice of messages without a pointer ``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ old │ new │ │ sec/op │ sec/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 3.193n ± 2% 3.242n ± 0% +1.50% (p=0.034 n=10) ObjectIDSlice/0_elements/from_grpc_message-8 3.197n ± 2% 3.343n ± 1% +4.57% (p=0.000 n=10) ObjectIDSlice/0_elements/marshal-8 5.666n ± 3% 5.642n ± 0% -0.42% (p=0.000 n=10) ObjectIDSlice/1_elements/to_grpc_message-8 53.10n ± 6% 29.78n ± 12% -43.92% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 28.99n ± 5% 29.77n ± 7% ~ (p=0.165 n=10) ObjectIDSlice/1_elements/marshal-8 49.08n ± 7% 50.72n ± 6% ~ (p=0.218 n=10) ObjectIDSlice/50_elements/to_grpc_message-8 1652.5n ± 7% 277.2n ± 1% -83.22% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 261.2n ± 11% 226.7n ± 15% -13.19% (p=0.003 n=10) ObjectIDSlice/50_elements/marshal-8 1.512µ ± 6% 1.514µ ± 6% ~ (p=0.955 n=10) geomean 52.15n 39.99n -23.31% │ old │ new │ │ B/op │ B/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/from_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/marshal-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/to_grpc_message-8 32.00 ± 0% 24.00 ± 0% -25.00% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 24.00 ± 0% 24.00 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/marshal-8 48.00 ± 0% 48.00 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/to_grpc_message-8 1.578Ki ± 0% 1.250Ki ± 0% -20.79% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 1.250Ki ± 0% 1.250Ki ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/marshal-8 2.000Ki ± 0% 2.000Ki ± 0% ~ (p=1.000 n=10) ¹ geomean ² -5.62% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ old │ new │ │ allocs/op │ allocs/op vs base │ ObjectIDSlice/0_elements/to_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/from_grpc_message-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/0_elements/marshal-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/to_grpc_message-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=10) ObjectIDSlice/1_elements/from_grpc_message-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/1_elements/marshal-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/to_grpc_message-8 51.000 ± 0% 1.000 ± 0% -98.04% (p=0.000 n=10) ObjectIDSlice/50_elements/from_grpc_message-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ ObjectIDSlice/50_elements/marshal-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² -40.18% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ``` Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2024-08-27 12:12:31 +00:00
} else {
g.P("if ", notNil(name), " {")
defer g.P("}")
}
g.P(name, ".EmitProtobuf(mm.AppendMessage(", f.Desc.Number(), "))")
return
}
method, cond := easyprotoKindInfo(f.Desc.Kind())
method = "Append" + method
if f.Desc.IsList() && !f.Desc.IsPacked() {
g.P("for j := range ", name, " {")
g.P("mm.", method, "(", f.Desc.Number(), ", ", name, "[j])")
g.P("}")
return
}
if f.Desc.IsList() {
method += "s"
g.P("if ", notEmpty(name), "{")
} else {
g.P("if ", cond(name), " {")
}
g.P("mm.", method, "(", f.Desc.Number(), ", ", name, ")")
g.P("}")
}