mirror of
https://github.com/genuinetools/reg.git
synced 2024-09-17 16:11:01 -04:00
675 lines
20 KiB
Go
675 lines
20 KiB
Go
|
// Protocol Buffers for Go with Gadgets
|
||
|
//
|
||
|
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
|
||
|
// http://github.com/gogo/protobuf
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions are
|
||
|
// met:
|
||
|
//
|
||
|
// * Redistributions of source code must retain the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer.
|
||
|
// * Redistributions in binary form must reproduce the above
|
||
|
// copyright notice, this list of conditions and the following disclaimer
|
||
|
// in the documentation and/or other materials provided with the
|
||
|
// distribution.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
||
|
/*
|
||
|
The size plugin generates a Size or ProtoSize method for each message.
|
||
|
This is useful with the MarshalTo method generated by the marshalto plugin and the
|
||
|
gogoproto.marshaler and gogoproto.marshaler_all extensions.
|
||
|
|
||
|
It is enabled by the following extensions:
|
||
|
|
||
|
- sizer
|
||
|
- sizer_all
|
||
|
- protosizer
|
||
|
- protosizer_all
|
||
|
|
||
|
The size plugin also generates a test given it is enabled using one of the following extensions:
|
||
|
|
||
|
- testgen
|
||
|
- testgen_all
|
||
|
|
||
|
And a benchmark given it is enabled using one of the following extensions:
|
||
|
|
||
|
- benchgen
|
||
|
- benchgen_all
|
||
|
|
||
|
Let us look at:
|
||
|
|
||
|
github.com/gogo/protobuf/test/example/example.proto
|
||
|
|
||
|
Btw all the output can be seen at:
|
||
|
|
||
|
github.com/gogo/protobuf/test/example/*
|
||
|
|
||
|
The following message:
|
||
|
|
||
|
option (gogoproto.sizer_all) = true;
|
||
|
|
||
|
message B {
|
||
|
option (gogoproto.description) = true;
|
||
|
optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
|
||
|
repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false];
|
||
|
}
|
||
|
|
||
|
given to the size plugin, will generate the following code:
|
||
|
|
||
|
func (m *B) Size() (n int) {
|
||
|
var l int
|
||
|
_ = l
|
||
|
l = m.A.Size()
|
||
|
n += 1 + l + sovExample(uint64(l))
|
||
|
if len(m.G) > 0 {
|
||
|
for _, e := range m.G {
|
||
|
l = e.Size()
|
||
|
n += 1 + l + sovExample(uint64(l))
|
||
|
}
|
||
|
}
|
||
|
if m.XXX_unrecognized != nil {
|
||
|
n += len(m.XXX_unrecognized)
|
||
|
}
|
||
|
return n
|
||
|
}
|
||
|
|
||
|
and the following test code:
|
||
|
|
||
|
func TestBSize(t *testing5.T) {
|
||
|
popr := math_rand5.New(math_rand5.NewSource(time5.Now().UnixNano()))
|
||
|
p := NewPopulatedB(popr, true)
|
||
|
dAtA, err := github_com_gogo_protobuf_proto2.Marshal(p)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
size := p.Size()
|
||
|
if len(dAtA) != size {
|
||
|
t.Fatalf("size %v != marshalled size %v", size, len(dAtA))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkBSize(b *testing5.B) {
|
||
|
popr := math_rand5.New(math_rand5.NewSource(616))
|
||
|
total := 0
|
||
|
pops := make([]*B, 1000)
|
||
|
for i := 0; i < 1000; i++ {
|
||
|
pops[i] = NewPopulatedB(popr, false)
|
||
|
}
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
total += pops[i%1000].Size()
|
||
|
}
|
||
|
b.SetBytes(int64(total / b.N))
|
||
|
}
|
||
|
|
||
|
The sovExample function is a size of varint function for the example.pb.go file.
|
||
|
|
||
|
*/
|
||
|
package size
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/gogo/protobuf/gogoproto"
|
||
|
"github.com/gogo/protobuf/proto"
|
||
|
descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
||
|
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
|
||
|
"github.com/gogo/protobuf/vanity"
|
||
|
)
|
||
|
|
||
|
type size struct {
|
||
|
*generator.Generator
|
||
|
generator.PluginImports
|
||
|
atleastOne bool
|
||
|
localName string
|
||
|
typesPkg generator.Single
|
||
|
}
|
||
|
|
||
|
func NewSize() *size {
|
||
|
return &size{}
|
||
|
}
|
||
|
|
||
|
func (p *size) Name() string {
|
||
|
return "size"
|
||
|
}
|
||
|
|
||
|
func (p *size) Init(g *generator.Generator) {
|
||
|
p.Generator = g
|
||
|
}
|
||
|
|
||
|
func wireToType(wire string) int {
|
||
|
switch wire {
|
||
|
case "fixed64":
|
||
|
return proto.WireFixed64
|
||
|
case "fixed32":
|
||
|
return proto.WireFixed32
|
||
|
case "varint":
|
||
|
return proto.WireVarint
|
||
|
case "bytes":
|
||
|
return proto.WireBytes
|
||
|
case "group":
|
||
|
return proto.WireBytes
|
||
|
case "zigzag32":
|
||
|
return proto.WireVarint
|
||
|
case "zigzag64":
|
||
|
return proto.WireVarint
|
||
|
}
|
||
|
panic("unreachable")
|
||
|
}
|
||
|
|
||
|
func keySize(fieldNumber int32, wireType int) int {
|
||
|
x := uint32(fieldNumber)<<3 | uint32(wireType)
|
||
|
size := 0
|
||
|
for size = 0; x > 127; size++ {
|
||
|
x >>= 7
|
||
|
}
|
||
|
size++
|
||
|
return size
|
||
|
}
|
||
|
|
||
|
func (p *size) sizeVarint() {
|
||
|
p.P(`
|
||
|
func sov`, p.localName, `(x uint64) (n int) {
|
||
|
for {
|
||
|
n++
|
||
|
x >>= 7
|
||
|
if x == 0 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return n
|
||
|
}`)
|
||
|
}
|
||
|
|
||
|
func (p *size) sizeZigZag() {
|
||
|
p.P(`func soz`, p.localName, `(x uint64) (n int) {
|
||
|
return sov`, p.localName, `(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||
|
}`)
|
||
|
}
|
||
|
|
||
|
func (p *size) std(field *descriptor.FieldDescriptorProto, name string) (string, bool) {
|
||
|
if gogoproto.IsStdTime(field) {
|
||
|
if gogoproto.IsNullable(field) {
|
||
|
return p.typesPkg.Use() + `.SizeOfStdTime(*` + name + `)`, true
|
||
|
} else {
|
||
|
return p.typesPkg.Use() + `.SizeOfStdTime(` + name + `)`, true
|
||
|
}
|
||
|
} else if gogoproto.IsStdDuration(field) {
|
||
|
if gogoproto.IsNullable(field) {
|
||
|
return p.typesPkg.Use() + `.SizeOfStdDuration(*` + name + `)`, true
|
||
|
} else {
|
||
|
return p.typesPkg.Use() + `.SizeOfStdDuration(` + name + `)`, true
|
||
|
}
|
||
|
}
|
||
|
return "", false
|
||
|
}
|
||
|
|
||
|
func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, sizeName string) {
|
||
|
fieldname := p.GetOneOfFieldName(message, field)
|
||
|
nullable := gogoproto.IsNullable(field)
|
||
|
repeated := field.IsRepeated()
|
||
|
doNilCheck := gogoproto.NeedsNilCheck(proto3, field)
|
||
|
if repeated {
|
||
|
p.P(`if len(m.`, fieldname, `) > 0 {`)
|
||
|
p.In()
|
||
|
} else if doNilCheck {
|
||
|
p.P(`if m.`, fieldname, ` != nil {`)
|
||
|
p.In()
|
||
|
}
|
||
|
packed := field.IsPacked() || (proto3 && field.IsPacked3())
|
||
|
_, wire := p.GoType(message, field)
|
||
|
wireType := wireToType(wire)
|
||
|
fieldNumber := field.GetNumber()
|
||
|
if packed {
|
||
|
wireType = proto.WireBytes
|
||
|
}
|
||
|
key := keySize(fieldNumber, wireType)
|
||
|
switch *field.Type {
|
||
|
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
|
||
|
if packed {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*8))`, `+len(m.`, fieldname, `)*8`)
|
||
|
} else if repeated {
|
||
|
p.P(`n+=`, strconv.Itoa(key+8), `*len(m.`, fieldname, `)`)
|
||
|
} else if proto3 {
|
||
|
p.P(`if m.`, fieldname, ` != 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key+8))
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`n+=`, strconv.Itoa(key+8))
|
||
|
} else {
|
||
|
p.P(`n+=`, strconv.Itoa(key+8))
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_FLOAT,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
|
||
|
if packed {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*4))`, `+len(m.`, fieldname, `)*4`)
|
||
|
} else if repeated {
|
||
|
p.P(`n+=`, strconv.Itoa(key+4), `*len(m.`, fieldname, `)`)
|
||
|
} else if proto3 {
|
||
|
p.P(`if m.`, fieldname, ` != 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key+4))
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`n+=`, strconv.Itoa(key+4))
|
||
|
} else {
|
||
|
p.P(`n+=`, strconv.Itoa(key+4))
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_INT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_ENUM,
|
||
|
descriptor.FieldDescriptorProto_TYPE_INT32:
|
||
|
if packed {
|
||
|
p.P(`l = 0`)
|
||
|
p.P(`for _, e := range m.`, fieldname, ` {`)
|
||
|
p.In()
|
||
|
p.P(`l+=sov`, p.localName, `(uint64(e))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(l))+l`)
|
||
|
} else if repeated {
|
||
|
p.P(`for _, e := range m.`, fieldname, ` {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(e))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if proto3 {
|
||
|
p.P(`if m.`, fieldname, ` != 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(m.`, fieldname, `))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(*m.`, fieldname, `))`)
|
||
|
} else {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(m.`, fieldname, `))`)
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_BOOL:
|
||
|
if packed {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)))`, `+len(m.`, fieldname, `)*1`)
|
||
|
} else if repeated {
|
||
|
p.P(`n+=`, strconv.Itoa(key+1), `*len(m.`, fieldname, `)`)
|
||
|
} else if proto3 {
|
||
|
p.P(`if m.`, fieldname, ` {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key+1))
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`n+=`, strconv.Itoa(key+1))
|
||
|
} else {
|
||
|
p.P(`n+=`, strconv.Itoa(key+1))
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_STRING:
|
||
|
if repeated {
|
||
|
p.P(`for _, s := range m.`, fieldname, ` { `)
|
||
|
p.In()
|
||
|
p.P(`l = len(s)`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if proto3 {
|
||
|
p.P(`l=len(m.`, fieldname, `)`)
|
||
|
p.P(`if l > 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`l=len(*m.`, fieldname, `)`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
} else {
|
||
|
p.P(`l=len(m.`, fieldname, `)`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_GROUP:
|
||
|
panic(fmt.Errorf("size does not support group %v", fieldname))
|
||
|
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
|
||
|
if p.IsMap(field) {
|
||
|
m := p.GoMapType(nil, field)
|
||
|
_, keywire := p.GoType(nil, m.KeyAliasField)
|
||
|
valuegoTyp, _ := p.GoType(nil, m.ValueField)
|
||
|
valuegoAliasTyp, valuewire := p.GoType(nil, m.ValueAliasField)
|
||
|
_, fieldwire := p.GoType(nil, field)
|
||
|
|
||
|
nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp)
|
||
|
|
||
|
fieldKeySize := keySize(field.GetNumber(), wireToType(fieldwire))
|
||
|
keyKeySize := keySize(1, wireToType(keywire))
|
||
|
valueKeySize := keySize(2, wireToType(valuewire))
|
||
|
p.P(`for k, v := range m.`, fieldname, ` { `)
|
||
|
p.In()
|
||
|
p.P(`_ = k`)
|
||
|
p.P(`_ = v`)
|
||
|
sum := []string{strconv.Itoa(keyKeySize)}
|
||
|
switch m.KeyField.GetType() {
|
||
|
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
|
||
|
sum = append(sum, `8`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_FLOAT,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
|
||
|
sum = append(sum, `4`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_INT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_ENUM,
|
||
|
descriptor.FieldDescriptorProto_TYPE_INT32:
|
||
|
sum = append(sum, `sov`+p.localName+`(uint64(k))`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_BOOL:
|
||
|
sum = append(sum, `1`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_STRING,
|
||
|
descriptor.FieldDescriptorProto_TYPE_BYTES:
|
||
|
sum = append(sum, `len(k)+sov`+p.localName+`(uint64(len(k)))`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_SINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SINT64:
|
||
|
sum = append(sum, `soz`+p.localName+`(uint64(k))`)
|
||
|
}
|
||
|
switch m.ValueField.GetType() {
|
||
|
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, strconv.Itoa(8))
|
||
|
case descriptor.FieldDescriptorProto_TYPE_FLOAT,
|
||
|
descriptor.FieldDescriptorProto_TYPE_FIXED32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, strconv.Itoa(4))
|
||
|
case descriptor.FieldDescriptorProto_TYPE_INT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT64,
|
||
|
descriptor.FieldDescriptorProto_TYPE_UINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_ENUM,
|
||
|
descriptor.FieldDescriptorProto_TYPE_INT32:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, `sov`+p.localName+`(uint64(v))`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_BOOL:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, `1`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_STRING:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, `len(v)+sov`+p.localName+`(uint64(len(v)))`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_BYTES:
|
||
|
if gogoproto.IsCustomType(field) {
|
||
|
p.P(`l = 0`)
|
||
|
if nullable {
|
||
|
p.P(`if v != nil {`)
|
||
|
p.In()
|
||
|
}
|
||
|
p.P(`l = v.`, sizeName, `()`)
|
||
|
p.P(`l += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(l))`)
|
||
|
if nullable {
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
sum = append(sum, `l`)
|
||
|
} else {
|
||
|
p.P(`l = 0`)
|
||
|
if proto3 {
|
||
|
p.P(`if len(v) > 0 {`)
|
||
|
} else {
|
||
|
p.P(`if v != nil {`)
|
||
|
}
|
||
|
p.In()
|
||
|
p.P(`l = `, strconv.Itoa(valueKeySize), ` + len(v)+sov`+p.localName+`(uint64(len(v)))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
sum = append(sum, `l`)
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_SINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SINT64:
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, `soz`+p.localName+`(uint64(v))`)
|
||
|
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
|
||
|
stdSizeCall, stdOk := p.std(field, "v")
|
||
|
if nullable {
|
||
|
p.P(`l = 0`)
|
||
|
p.P(`if v != nil {`)
|
||
|
p.In()
|
||
|
if stdOk {
|
||
|
p.P(`l = `, stdSizeCall)
|
||
|
} else if valuegoTyp != valuegoAliasTyp {
|
||
|
p.P(`l = ((`, valuegoTyp, `)(v)).`, sizeName, `()`)
|
||
|
} else {
|
||
|
p.P(`l = v.`, sizeName, `()`)
|
||
|
}
|
||
|
p.P(`l += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
sum = append(sum, `l`)
|
||
|
} else {
|
||
|
if stdOk {
|
||
|
p.P(`l = `, stdSizeCall)
|
||
|
} else if valuegoTyp != valuegoAliasTyp {
|
||
|
p.P(`l = ((*`, valuegoTyp, `)(&v)).`, sizeName, `()`)
|
||
|
} else {
|
||
|
p.P(`l = v.`, sizeName, `()`)
|
||
|
}
|
||
|
sum = append(sum, strconv.Itoa(valueKeySize))
|
||
|
sum = append(sum, `l+sov`+p.localName+`(uint64(l))`)
|
||
|
}
|
||
|
}
|
||
|
p.P(`mapEntrySize := `, strings.Join(sum, "+"))
|
||
|
p.P(`n+=mapEntrySize+`, fieldKeySize, `+sov`, p.localName, `(uint64(mapEntrySize))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if repeated {
|
||
|
p.P(`for _, e := range m.`, fieldname, ` { `)
|
||
|
p.In()
|
||
|
stdSizeCall, stdOk := p.std(field, "e")
|
||
|
if stdOk {
|
||
|
p.P(`l=`, stdSizeCall)
|
||
|
} else {
|
||
|
p.P(`l=e.`, sizeName, `()`)
|
||
|
}
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else {
|
||
|
stdSizeCall, stdOk := p.std(field, "m."+fieldname)
|
||
|
if stdOk {
|
||
|
p.P(`l=`, stdSizeCall)
|
||
|
} else {
|
||
|
p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
|
||
|
}
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_BYTES:
|
||
|
if !gogoproto.IsCustomType(field) {
|
||
|
if repeated {
|
||
|
p.P(`for _, b := range m.`, fieldname, ` { `)
|
||
|
p.In()
|
||
|
p.P(`l = len(b)`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if proto3 {
|
||
|
p.P(`l=len(m.`, fieldname, `)`)
|
||
|
p.P(`if l > 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else {
|
||
|
p.P(`l=len(m.`, fieldname, `)`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
}
|
||
|
} else {
|
||
|
if repeated {
|
||
|
p.P(`for _, e := range m.`, fieldname, ` { `)
|
||
|
p.In()
|
||
|
p.P(`l=e.`, sizeName, `()`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else {
|
||
|
p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
|
||
|
}
|
||
|
}
|
||
|
case descriptor.FieldDescriptorProto_TYPE_SINT32,
|
||
|
descriptor.FieldDescriptorProto_TYPE_SINT64:
|
||
|
if packed {
|
||
|
p.P(`l = 0`)
|
||
|
p.P(`for _, e := range m.`, fieldname, ` {`)
|
||
|
p.In()
|
||
|
p.P(`l+=soz`, p.localName, `(uint64(e))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(l))+l`)
|
||
|
} else if repeated {
|
||
|
p.P(`for _, e := range m.`, fieldname, ` {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(e))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if proto3 {
|
||
|
p.P(`if m.`, fieldname, ` != 0 {`)
|
||
|
p.In()
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(m.`, fieldname, `))`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
} else if nullable {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(*m.`, fieldname, `))`)
|
||
|
} else {
|
||
|
p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(m.`, fieldname, `))`)
|
||
|
}
|
||
|
default:
|
||
|
panic("not implemented")
|
||
|
}
|
||
|
if repeated || doNilCheck {
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (p *size) Generate(file *generator.FileDescriptor) {
|
||
|
p.PluginImports = generator.NewPluginImports(p.Generator)
|
||
|
p.atleastOne = false
|
||
|
p.localName = generator.FileName(file)
|
||
|
p.typesPkg = p.NewImport("github.com/gogo/protobuf/types")
|
||
|
protoPkg := p.NewImport("github.com/gogo/protobuf/proto")
|
||
|
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
|
||
|
protoPkg = p.NewImport("github.com/golang/protobuf/proto")
|
||
|
}
|
||
|
for _, message := range file.Messages() {
|
||
|
sizeName := ""
|
||
|
if gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) && gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
|
||
|
fmt.Fprintf(os.Stderr, "ERROR: message %v cannot support both sizer and protosizer plugins\n", generator.CamelCase(*message.Name))
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
if gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) {
|
||
|
sizeName = "Size"
|
||
|
} else if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
|
||
|
sizeName = "ProtoSize"
|
||
|
} else {
|
||
|
continue
|
||
|
}
|
||
|
if message.DescriptorProto.GetOptions().GetMapEntry() {
|
||
|
continue
|
||
|
}
|
||
|
p.atleastOne = true
|
||
|
ccTypeName := generator.CamelCaseSlice(message.TypeName())
|
||
|
p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`)
|
||
|
p.In()
|
||
|
p.P(`var l int`)
|
||
|
p.P(`_ = l`)
|
||
|
oneofs := make(map[string]struct{})
|
||
|
for _, field := range message.Field {
|
||
|
oneof := field.OneofIndex != nil
|
||
|
if !oneof {
|
||
|
proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
|
||
|
p.generateField(proto3, file, message, field, sizeName)
|
||
|
} else {
|
||
|
fieldname := p.GetFieldName(message, field)
|
||
|
if _, ok := oneofs[fieldname]; ok {
|
||
|
continue
|
||
|
} else {
|
||
|
oneofs[fieldname] = struct{}{}
|
||
|
}
|
||
|
p.P(`if m.`, fieldname, ` != nil {`)
|
||
|
p.In()
|
||
|
p.P(`n+=m.`, fieldname, `.`, sizeName, `()`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
}
|
||
|
if message.DescriptorProto.HasExtension() {
|
||
|
if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) {
|
||
|
p.P(`n += `, protoPkg.Use(), `.SizeOfInternalExtension(m)`)
|
||
|
} else {
|
||
|
p.P(`if m.XXX_extensions != nil {`)
|
||
|
p.In()
|
||
|
p.P(`n+=len(m.XXX_extensions)`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
}
|
||
|
if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) {
|
||
|
p.P(`if m.XXX_unrecognized != nil {`)
|
||
|
p.In()
|
||
|
p.P(`n+=len(m.XXX_unrecognized)`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
p.P(`return n`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
p.P()
|
||
|
|
||
|
//Generate Size methods for oneof fields
|
||
|
m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto)
|
||
|
for _, f := range m.Field {
|
||
|
oneof := f.OneofIndex != nil
|
||
|
if !oneof {
|
||
|
continue
|
||
|
}
|
||
|
ccTypeName := p.OneOfTypeName(message, f)
|
||
|
p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`)
|
||
|
p.In()
|
||
|
p.P(`var l int`)
|
||
|
p.P(`_ = l`)
|
||
|
vanity.TurnOffNullableForNativeTypes(f)
|
||
|
p.generateField(false, file, message, f, sizeName)
|
||
|
p.P(`return n`)
|
||
|
p.Out()
|
||
|
p.P(`}`)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !p.atleastOne {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
p.sizeVarint()
|
||
|
p.sizeZigZag()
|
||
|
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
generator.RegisterPlugin(NewSize())
|
||
|
}
|