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: "", }