You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1205 lines
36 KiB
1205 lines
36 KiB
// 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 marshalto plugin generates a Marshal and MarshalTo method for each message. |
|
The `Marshal() ([]byte, error)` method results in the fact that the message |
|
implements the Marshaler interface. |
|
This allows proto.Marshal to be faster by calling the generated Marshal method rather than using reflect to Marshal the struct. |
|
|
|
If is enabled by the following extensions: |
|
|
|
- marshaler |
|
- marshaler_all |
|
|
|
Or the following extensions: |
|
|
|
- unsafe_marshaler |
|
- unsafe_marshaler_all |
|
|
|
That is if you want to use the unsafe package in your generated code. |
|
The speed up using the unsafe package is not very significant. |
|
|
|
The generation of marshalling tests are enabled using one of the following extensions: |
|
|
|
- testgen |
|
- testgen_all |
|
|
|
And benchmarks 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.marshaler_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 marshalto plugin, will generate the following code: |
|
|
|
func (m *B) Marshal() (dAtA []byte, err error) { |
|
size := m.Size() |
|
dAtA = make([]byte, size) |
|
n, err := m.MarshalTo(dAtA) |
|
if err != nil { |
|
return nil, err |
|
} |
|
return dAtA[:n], nil |
|
} |
|
|
|
func (m *B) MarshalTo(dAtA []byte) (int, error) { |
|
var i int |
|
_ = i |
|
var l int |
|
_ = l |
|
dAtA[i] = 0xa |
|
i++ |
|
i = encodeVarintExample(dAtA, i, uint64(m.A.Size())) |
|
n2, err := m.A.MarshalTo(dAtA[i:]) |
|
if err != nil { |
|
return 0, err |
|
} |
|
i += n2 |
|
if len(m.G) > 0 { |
|
for _, msg := range m.G { |
|
dAtA[i] = 0x12 |
|
i++ |
|
i = encodeVarintExample(dAtA, i, uint64(msg.Size())) |
|
n, err := msg.MarshalTo(dAtA[i:]) |
|
if err != nil { |
|
return 0, err |
|
} |
|
i += n |
|
} |
|
} |
|
if m.XXX_unrecognized != nil { |
|
i += copy(dAtA[i:], m.XXX_unrecognized) |
|
} |
|
return i, nil |
|
} |
|
|
|
As shown above Marshal calculates the size of the not yet marshalled message |
|
and allocates the appropriate buffer. |
|
This is followed by calling the MarshalTo method which requires a preallocated buffer. |
|
The MarshalTo method allows a user to rather preallocated a reusable buffer. |
|
|
|
The Size method is generated using the size plugin and the gogoproto.sizer, gogoproto.sizer_all extensions. |
|
The user can also using the generated Size method to check that his reusable buffer is still big enough. |
|
|
|
The generated tests and benchmarks will keep you safe and show that this is really a significant speed improvement. |
|
|
|
An additional message-level option `stable_marshaler` (and the file-level |
|
option `stable_marshaler_all`) exists which causes the generated marshalling |
|
code to behave deterministically. Today, this only changes the serialization of |
|
maps; they are serialized in sort order. |
|
*/ |
|
package marshalto |
|
|
|
import ( |
|
"fmt" |
|
"sort" |
|
"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 NumGen interface { |
|
Next() string |
|
Current() string |
|
} |
|
|
|
type numGen struct { |
|
index int |
|
} |
|
|
|
func NewNumGen() NumGen { |
|
return &numGen{0} |
|
} |
|
|
|
func (this *numGen) Next() string { |
|
this.index++ |
|
return this.Current() |
|
} |
|
|
|
func (this *numGen) Current() string { |
|
return strconv.Itoa(this.index) |
|
} |
|
|
|
type marshalto struct { |
|
*generator.Generator |
|
generator.PluginImports |
|
atleastOne bool |
|
errorsPkg generator.Single |
|
protoPkg generator.Single |
|
sortKeysPkg generator.Single |
|
mathPkg generator.Single |
|
typesPkg generator.Single |
|
binaryPkg generator.Single |
|
localName string |
|
} |
|
|
|
func NewMarshal() *marshalto { |
|
return &marshalto{} |
|
} |
|
|
|
func (p *marshalto) Name() string { |
|
return "marshalto" |
|
} |
|
|
|
func (p *marshalto) Init(g *generator.Generator) { |
|
p.Generator = g |
|
} |
|
|
|
func (p *marshalto) callFixed64(varName ...string) { |
|
p.P(p.binaryPkg.Use(), `.LittleEndian.PutUint64(dAtA[i:], uint64(`, strings.Join(varName, ""), `))`) |
|
p.P(`i += 8`) |
|
} |
|
|
|
func (p *marshalto) callFixed32(varName ...string) { |
|
p.P(p.binaryPkg.Use(), `.LittleEndian.PutUint32(dAtA[i:], uint32(`, strings.Join(varName, ""), `))`) |
|
p.P(`i += 4`) |
|
} |
|
|
|
func (p *marshalto) callVarint(varName ...string) { |
|
p.P(`i = encodeVarint`, p.localName, `(dAtA, i, uint64(`, strings.Join(varName, ""), `))`) |
|
} |
|
|
|
func (p *marshalto) encodeVarint(varName string) { |
|
p.P(`for `, varName, ` >= 1<<7 {`) |
|
p.In() |
|
p.P(`dAtA[i] = uint8(uint64(`, varName, `)&0x7f|0x80)`) |
|
p.P(varName, ` >>= 7`) |
|
p.P(`i++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`dAtA[i] = uint8(`, varName, `)`) |
|
p.P(`i++`) |
|
} |
|
|
|
func (p *marshalto) encodeKey(fieldNumber int32, wireType int) { |
|
x := uint32(fieldNumber)<<3 | uint32(wireType) |
|
i := 0 |
|
keybuf := make([]byte, 0) |
|
for i = 0; x > 127; i++ { |
|
keybuf = append(keybuf, 0x80|uint8(x&0x7F)) |
|
x >>= 7 |
|
} |
|
keybuf = append(keybuf, uint8(x)) |
|
for _, b := range keybuf { |
|
p.P(`dAtA[i] = `, fmt.Sprintf("%#v", b)) |
|
p.P(`i++`) |
|
} |
|
} |
|
|
|
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 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 (p *marshalto) mapField(numGen NumGen, field *descriptor.FieldDescriptorProto, kvField *descriptor.FieldDescriptorProto, varName string, protoSizer bool) { |
|
switch kvField.GetType() { |
|
case descriptor.FieldDescriptorProto_TYPE_DOUBLE: |
|
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(`, varName, `))`) |
|
case descriptor.FieldDescriptorProto_TYPE_FLOAT: |
|
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(`, varName, `))`) |
|
case descriptor.FieldDescriptorProto_TYPE_INT64, |
|
descriptor.FieldDescriptorProto_TYPE_UINT64, |
|
descriptor.FieldDescriptorProto_TYPE_INT32, |
|
descriptor.FieldDescriptorProto_TYPE_UINT32, |
|
descriptor.FieldDescriptorProto_TYPE_ENUM: |
|
p.callVarint(varName) |
|
case descriptor.FieldDescriptorProto_TYPE_FIXED64, |
|
descriptor.FieldDescriptorProto_TYPE_SFIXED64: |
|
p.callFixed64(varName) |
|
case descriptor.FieldDescriptorProto_TYPE_FIXED32, |
|
descriptor.FieldDescriptorProto_TYPE_SFIXED32: |
|
p.callFixed32(varName) |
|
case descriptor.FieldDescriptorProto_TYPE_BOOL: |
|
p.P(`if `, varName, ` {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
case descriptor.FieldDescriptorProto_TYPE_STRING, |
|
descriptor.FieldDescriptorProto_TYPE_BYTES: |
|
if gogoproto.IsCustomType(field) && kvField.IsBytes() { |
|
p.callVarint(varName, `.Size()`) |
|
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`, numGen.Current()) |
|
} else { |
|
p.callVarint(`len(`, varName, `)`) |
|
p.P(`i+=copy(dAtA[i:], `, varName, `)`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_SINT32: |
|
p.callVarint(`(uint32(`, varName, `) << 1) ^ uint32((`, varName, ` >> 31))`) |
|
case descriptor.FieldDescriptorProto_TYPE_SINT64: |
|
p.callVarint(`(uint64(`, varName, `) << 1) ^ uint64((`, varName, ` >> 63))`) |
|
case descriptor.FieldDescriptorProto_TYPE_MESSAGE: |
|
if gogoproto.IsStdTime(field) { |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdTime(*`, varName, `)`) |
|
p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdTimeMarshalTo(*`, varName, `, dAtA[i:])`) |
|
} else if gogoproto.IsStdDuration(field) { |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdDuration(*`, varName, `)`) |
|
p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdDurationMarshalTo(*`, varName, `, dAtA[i:])`) |
|
} else if protoSizer { |
|
p.callVarint(varName, `.ProtoSize()`) |
|
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} else { |
|
p.callVarint(varName, `.Size()`) |
|
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`, numGen.Current()) |
|
} |
|
} |
|
|
|
type orderFields []*descriptor.FieldDescriptorProto |
|
|
|
func (this orderFields) Len() int { |
|
return len(this) |
|
} |
|
|
|
func (this orderFields) Less(i, j int) bool { |
|
return this[i].GetNumber() < this[j].GetNumber() |
|
} |
|
|
|
func (this orderFields) Swap(i, j int) { |
|
this[i], this[j] = this[j], this[i] |
|
} |
|
|
|
func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) { |
|
fieldname := p.GetOneOfFieldName(message, field) |
|
nullable := gogoproto.IsNullable(field) |
|
repeated := field.IsRepeated() |
|
required := field.IsRequired() |
|
|
|
protoSizer := gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) |
|
doNilCheck := gogoproto.NeedsNilCheck(proto3, field) |
|
if required && nullable { |
|
p.P(`if m.`, fieldname, `== nil {`) |
|
p.In() |
|
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { |
|
p.P(`return 0, new(`, p.protoPkg.Use(), `.RequiredNotSetError)`) |
|
} else { |
|
p.P(`return 0, `, p.protoPkg.Use(), `.NewRequiredNotSetError("`, field.GetName(), `")`) |
|
} |
|
p.Out() |
|
p.P(`} else {`) |
|
} else 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()) |
|
wireType := field.WireType() |
|
fieldNumber := field.GetNumber() |
|
if packed { |
|
wireType = proto.WireBytes |
|
} |
|
switch *field.Type { |
|
case descriptor.FieldDescriptorProto_TYPE_DOUBLE: |
|
if packed { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `) * 8`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`) |
|
p.callFixed64("f" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`) |
|
p.callFixed64("f" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(*m.`+fieldname, `))`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_FLOAT: |
|
if packed { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `) * 4`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`) |
|
p.callFixed32("f" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`) |
|
p.callFixed32("f" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(*m.`+fieldname, `))`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_INT64, |
|
descriptor.FieldDescriptorProto_TYPE_UINT64, |
|
descriptor.FieldDescriptorProto_TYPE_INT32, |
|
descriptor.FieldDescriptorProto_TYPE_UINT32, |
|
descriptor.FieldDescriptorProto_TYPE_ENUM: |
|
if packed { |
|
jvar := "j" + numGen.Next() |
|
p.P(`dAtA`, numGen.Next(), ` := make([]byte, len(m.`, fieldname, `)*10)`) |
|
p.P(`var `, jvar, ` int`) |
|
if *field.Type == descriptor.FieldDescriptorProto_TYPE_INT64 || |
|
*field.Type == descriptor.FieldDescriptorProto_TYPE_INT32 { |
|
p.P(`for _, num1 := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`num := uint64(num1)`) |
|
} else { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
} |
|
p.P(`for num >= 1<<7 {`) |
|
p.In() |
|
p.P(`dAtA`, numGen.Current(), `[`, jvar, `] = uint8(uint64(num)&0x7f|0x80)`) |
|
p.P(`num >>= 7`) |
|
p.P(jvar, `++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`dAtA`, numGen.Current(), `[`, jvar, `] = uint8(num)`) |
|
p.P(jvar, `++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(jvar) |
|
p.P(`i += copy(dAtA[i:], dAtA`, numGen.Current(), `[:`, jvar, `])`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint("num") |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`m.`, fieldname) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`m.`, fieldname) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`*m.`, fieldname) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_FIXED64, |
|
descriptor.FieldDescriptorProto_TYPE_SFIXED64: |
|
if packed { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `) * 8`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.callFixed64("num") |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64("num") |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64("m." + fieldname) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64("m." + fieldname) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed64("*m." + fieldname) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_FIXED32, |
|
descriptor.FieldDescriptorProto_TYPE_SFIXED32: |
|
if packed { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `) * 4`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.callFixed32("num") |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32("num") |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32("m." + fieldname) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32("m." + fieldname) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callFixed32("*m." + fieldname) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_BOOL: |
|
if packed { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `)`) |
|
p.P(`for _, b := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`if b {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, b := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`if b {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`if m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`if m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`if *m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(`dAtA[i] = 1`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
p.P(`dAtA[i] = 0`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i++`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_STRING: |
|
if repeated { |
|
p.P(`for _, s := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`l = len(s)`) |
|
p.encodeVarint("l") |
|
p.P(`i+=copy(dAtA[i:], s)`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if len(m.`, fieldname, `) > 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `)`) |
|
p.P(`i+=copy(dAtA[i:], m.`, fieldname, `)`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `)`) |
|
p.P(`i+=copy(dAtA[i:], m.`, fieldname, `)`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(*m.`, fieldname, `)`) |
|
p.P(`i+=copy(dAtA[i:], *m.`, fieldname, `)`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_GROUP: |
|
panic(fmt.Errorf("marshaler does not support group %v", fieldname)) |
|
case descriptor.FieldDescriptorProto_TYPE_MESSAGE: |
|
if p.IsMap(field) { |
|
m := p.GoMapType(nil, field) |
|
keygoTyp, keywire := p.GoType(nil, m.KeyField) |
|
keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField) |
|
// keys may not be pointers |
|
keygoTyp = strings.Replace(keygoTyp, "*", "", 1) |
|
keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) |
|
keyCapTyp := generator.CamelCase(keygoTyp) |
|
valuegoTyp, valuewire := p.GoType(nil, m.ValueField) |
|
valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) |
|
nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) |
|
keyKeySize := keySize(1, wireToType(keywire)) |
|
valueKeySize := keySize(2, wireToType(valuewire)) |
|
if gogoproto.IsStableMarshaler(file.FileDescriptorProto, message.DescriptorProto) { |
|
keysName := `keysFor` + fieldname |
|
p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(m.`, fieldname, `))`) |
|
p.P(`for k, _ := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(keysName, ` = append(`, keysName, `, `, keygoTyp, `(k))`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(p.sortKeysPkg.Use(), `.`, keyCapTyp, `s(`, keysName, `)`) |
|
p.P(`for _, k := range `, keysName, ` {`) |
|
} else { |
|
p.P(`for k, _ := range m.`, fieldname, ` {`) |
|
} |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
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))`) |
|
} |
|
if gogoproto.IsStableMarshaler(file.FileDescriptorProto, message.DescriptorProto) { |
|
p.P(`v := m.`, fieldname, `[`, keygoAliasTyp, `(k)]`) |
|
} else { |
|
p.P(`v := m.`, fieldname, `[k]`) |
|
} |
|
accessor := `v` |
|
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(`cSize := 0`) |
|
if gogoproto.IsNullable(field) { |
|
p.P(`if `, accessor, ` != nil {`) |
|
p.In() |
|
} |
|
p.P(`cSize = `, accessor, `.Size()`) |
|
p.P(`cSize += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(cSize))`) |
|
if gogoproto.IsNullable(field) { |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
sum = append(sum, `cSize`) |
|
} else { |
|
p.P(`byteSize := 0`) |
|
if proto3 { |
|
p.P(`if len(v) > 0 {`) |
|
} else { |
|
p.P(`if v != nil {`) |
|
} |
|
p.In() |
|
p.P(`byteSize = `, strconv.Itoa(valueKeySize), ` + len(v)+sov`+p.localName+`(uint64(len(v)))`) |
|
p.Out() |
|
p.P(`}`) |
|
sum = append(sum, `byteSize`) |
|
} |
|
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: |
|
if valuegoTyp != valuegoAliasTyp && |
|
!gogoproto.IsStdTime(field) && |
|
!gogoproto.IsStdDuration(field) { |
|
if nullable { |
|
// cast back to the type that has the generated methods on it |
|
accessor = `((` + valuegoTyp + `)(` + accessor + `))` |
|
} else { |
|
accessor = `((*` + valuegoTyp + `)(&` + accessor + `))` |
|
} |
|
} else if !nullable { |
|
accessor = `(&v)` |
|
} |
|
p.P(`msgSize := 0`) |
|
p.P(`if `, accessor, ` != nil {`) |
|
p.In() |
|
if gogoproto.IsStdTime(field) { |
|
p.P(`msgSize = `, p.typesPkg.Use(), `.SizeOfStdTime(*`, accessor, `)`) |
|
} else if gogoproto.IsStdDuration(field) { |
|
p.P(`msgSize = `, p.typesPkg.Use(), `.SizeOfStdDuration(*`, accessor, `)`) |
|
} else if protoSizer { |
|
p.P(`msgSize = `, accessor, `.ProtoSize()`) |
|
} else { |
|
p.P(`msgSize = `, accessor, `.Size()`) |
|
} |
|
p.P(`msgSize += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(msgSize))`) |
|
p.Out() |
|
p.P(`}`) |
|
sum = append(sum, `msgSize`) |
|
} |
|
p.P(`mapSize := `, strings.Join(sum, " + ")) |
|
p.callVarint("mapSize") |
|
p.encodeKey(1, wireToType(keywire)) |
|
p.mapField(numGen, field, m.KeyField, "k", protoSizer) |
|
nullableMsg := nullable && (m.ValueField.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE || |
|
gogoproto.IsCustomType(field) && m.ValueField.IsBytes()) |
|
plainBytes := m.ValueField.IsBytes() && !gogoproto.IsCustomType(field) |
|
if nullableMsg { |
|
p.P(`if `, accessor, ` != nil { `) |
|
p.In() |
|
} else if plainBytes { |
|
if proto3 { |
|
p.P(`if len(`, accessor, `) > 0 {`) |
|
} else { |
|
p.P(`if `, accessor, ` != nil {`) |
|
} |
|
p.In() |
|
} |
|
p.encodeKey(2, wireToType(valuewire)) |
|
p.mapField(numGen, field, m.ValueField, accessor, protoSizer) |
|
if nullableMsg || plainBytes { |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} else if repeated { |
|
p.P(`for _, msg := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
varName := "msg" |
|
if gogoproto.IsStdTime(field) { |
|
if gogoproto.IsNullable(field) { |
|
varName = "*" + varName |
|
} |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdTime(`, varName, `)`) |
|
p.P(`n, err := `, p.typesPkg.Use(), `.StdTimeMarshalTo(`, varName, `, dAtA[i:])`) |
|
} else if gogoproto.IsStdDuration(field) { |
|
if gogoproto.IsNullable(field) { |
|
varName = "*" + varName |
|
} |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdDuration(`, varName, `)`) |
|
p.P(`n, err := `, p.typesPkg.Use(), `.StdDurationMarshalTo(`, varName, `, dAtA[i:])`) |
|
} else if protoSizer { |
|
p.callVarint(varName, ".ProtoSize()") |
|
p.P(`n, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} else { |
|
p.callVarint(varName, ".Size()") |
|
p.P(`n, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`) |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
varName := `m.` + fieldname |
|
if gogoproto.IsStdTime(field) { |
|
if gogoproto.IsNullable(field) { |
|
varName = "*" + varName |
|
} |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdTime(`, varName, `)`) |
|
p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdTimeMarshalTo(`, varName, `, dAtA[i:])`) |
|
} else if gogoproto.IsStdDuration(field) { |
|
if gogoproto.IsNullable(field) { |
|
varName = "*" + varName |
|
} |
|
p.callVarint(p.typesPkg.Use(), `.SizeOfStdDuration(`, varName, `)`) |
|
p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdDurationMarshalTo(`, varName, `, dAtA[i:])`) |
|
} else if protoSizer { |
|
p.callVarint(varName, `.ProtoSize()`) |
|
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} else { |
|
p.callVarint(varName, `.Size()`) |
|
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(dAtA[i:])`) |
|
} |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`, numGen.Current()) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_BYTES: |
|
if !gogoproto.IsCustomType(field) { |
|
if repeated { |
|
p.P(`for _, b := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint("len(b)") |
|
p.P(`i+=copy(dAtA[i:], b)`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if len(m.`, fieldname, `) > 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `)`) |
|
p.P(`i+=copy(dAtA[i:], m.`, fieldname, `)`) |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`len(m.`, fieldname, `)`) |
|
p.P(`i+=copy(dAtA[i:], m.`, fieldname, `)`) |
|
} |
|
} else { |
|
if repeated { |
|
p.P(`for _, msg := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
if protoSizer { |
|
p.callVarint(`msg.ProtoSize()`) |
|
} else { |
|
p.callVarint(`msg.Size()`) |
|
} |
|
p.P(`n, err := msg.MarshalTo(dAtA[i:])`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`) |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
if protoSizer { |
|
p.callVarint(`m.`, fieldname, `.ProtoSize()`) |
|
} else { |
|
p.callVarint(`m.`, fieldname, `.Size()`) |
|
} |
|
p.P(`n`, numGen.Next(), `, err := m.`, fieldname, `.MarshalTo(dAtA[i:])`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`, numGen.Current()) |
|
} |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_SINT32: |
|
if packed { |
|
datavar := "dAtA" + numGen.Next() |
|
jvar := "j" + numGen.Next() |
|
p.P(datavar, ` := make([]byte, len(m.`, fieldname, ")*5)") |
|
p.P(`var `, jvar, ` int`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
xvar := "x" + numGen.Next() |
|
p.P(xvar, ` := (uint32(num) << 1) ^ uint32((num >> 31))`) |
|
p.P(`for `, xvar, ` >= 1<<7 {`) |
|
p.In() |
|
p.P(datavar, `[`, jvar, `] = uint8(uint64(`, xvar, `)&0x7f|0x80)`) |
|
p.P(jvar, `++`) |
|
p.P(xvar, ` >>= 7`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(datavar, `[`, jvar, `] = uint8(`, xvar, `)`) |
|
p.P(jvar, `++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(jvar) |
|
p.P(`i+=copy(dAtA[i:], `, datavar, `[:`, jvar, `])`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`x`, numGen.Next(), ` := (uint32(num) << 1) ^ uint32((num >> 31))`) |
|
p.encodeVarint("x" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint32(m.`, fieldname, `) << 1) ^ uint32((m.`, fieldname, ` >> 31))`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint32(m.`, fieldname, `) << 1) ^ uint32((m.`, fieldname, ` >> 31))`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint32(*m.`, fieldname, `) << 1) ^ uint32((*m.`, fieldname, ` >> 31))`) |
|
} |
|
case descriptor.FieldDescriptorProto_TYPE_SINT64: |
|
if packed { |
|
jvar := "j" + numGen.Next() |
|
xvar := "x" + numGen.Next() |
|
datavar := "dAtA" + numGen.Next() |
|
p.P(`var `, jvar, ` int`) |
|
p.P(datavar, ` := make([]byte, len(m.`, fieldname, `)*10)`) |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.P(xvar, ` := (uint64(num) << 1) ^ uint64((num >> 63))`) |
|
p.P(`for `, xvar, ` >= 1<<7 {`) |
|
p.In() |
|
p.P(datavar, `[`, jvar, `] = uint8(uint64(`, xvar, `)&0x7f|0x80)`) |
|
p.P(jvar, `++`) |
|
p.P(xvar, ` >>= 7`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(datavar, `[`, jvar, `] = uint8(`, xvar, `)`) |
|
p.P(jvar, `++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(jvar) |
|
p.P(`i+=copy(dAtA[i:], `, datavar, `[:`, jvar, `])`) |
|
} else if repeated { |
|
p.P(`for _, num := range m.`, fieldname, ` {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.P(`x`, numGen.Next(), ` := (uint64(num) << 1) ^ uint64((num >> 63))`) |
|
p.encodeVarint("x" + numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} else if proto3 { |
|
p.P(`if m.`, fieldname, ` != 0 {`) |
|
p.In() |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint64(m.`, fieldname, `) << 1) ^ uint64((m.`, fieldname, ` >> 63))`) |
|
p.Out() |
|
p.P(`}`) |
|
} else if !nullable { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint64(m.`, fieldname, `) << 1) ^ uint64((m.`, fieldname, ` >> 63))`) |
|
} else { |
|
p.encodeKey(fieldNumber, wireType) |
|
p.callVarint(`(uint64(*m.`, fieldname, `) << 1) ^ uint64((*m.`, fieldname, ` >> 63))`) |
|
} |
|
default: |
|
panic("not implemented") |
|
} |
|
if (required && nullable) || repeated || doNilCheck { |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
|
|
func (p *marshalto) Generate(file *generator.FileDescriptor) { |
|
numGen := NewNumGen() |
|
p.PluginImports = generator.NewPluginImports(p.Generator) |
|
|
|
p.atleastOne = false |
|
p.localName = generator.FileName(file) |
|
|
|
p.mathPkg = p.NewImport("math") |
|
p.sortKeysPkg = p.NewImport("github.com/gogo/protobuf/sortkeys") |
|
p.protoPkg = p.NewImport("github.com/gogo/protobuf/proto") |
|
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { |
|
p.protoPkg = p.NewImport("github.com/golang/protobuf/proto") |
|
} |
|
p.errorsPkg = p.NewImport("errors") |
|
p.binaryPkg = p.NewImport("encoding/binary") |
|
p.typesPkg = p.NewImport("github.com/gogo/protobuf/types") |
|
|
|
for _, message := range file.Messages() { |
|
if message.DescriptorProto.GetOptions().GetMapEntry() { |
|
continue |
|
} |
|
ccTypeName := generator.CamelCaseSlice(message.TypeName()) |
|
if !gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) && |
|
!gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) { |
|
continue |
|
} |
|
p.atleastOne = true |
|
|
|
p.P(`func (m *`, ccTypeName, `) Marshal() (dAtA []byte, err error) {`) |
|
p.In() |
|
if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) { |
|
p.P(`size := m.ProtoSize()`) |
|
} else { |
|
p.P(`size := m.Size()`) |
|
} |
|
p.P(`dAtA = make([]byte, size)`) |
|
p.P(`n, err := m.MarshalTo(dAtA)`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return nil, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`return dAtA[:n], nil`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(``) |
|
p.P(`func (m *`, ccTypeName, `) MarshalTo(dAtA []byte) (int, error) {`) |
|
p.In() |
|
p.P(`var i int`) |
|
p.P(`_ = i`) |
|
p.P(`var l int`) |
|
p.P(`_ = l`) |
|
fields := orderFields(message.GetField()) |
|
sort.Sort(fields) |
|
oneofs := make(map[string]struct{}) |
|
for _, field := range message.Field { |
|
oneof := field.OneofIndex != nil |
|
if !oneof { |
|
proto3 := gogoproto.IsProto3(file.FileDescriptorProto) |
|
p.generateField(proto3, numGen, file, message, field) |
|
} else { |
|
fieldname := p.GetFieldName(message, field) |
|
if _, ok := oneofs[fieldname]; !ok { |
|
oneofs[fieldname] = struct{}{} |
|
p.P(`if m.`, fieldname, ` != nil {`) |
|
p.In() |
|
p.P(`nn`, numGen.Next(), `, err := m.`, fieldname, `.MarshalTo(dAtA[i:])`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=nn`, numGen.Current()) |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
} |
|
if message.DescriptorProto.HasExtension() { |
|
if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { |
|
p.P(`n, err := `, p.protoPkg.Use(), `.EncodeInternalExtension(m, dAtA[i:])`) |
|
p.P(`if err != nil {`) |
|
p.In() |
|
p.P(`return 0, err`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`i+=n`) |
|
} else { |
|
p.P(`if m.XXX_extensions != nil {`) |
|
p.In() |
|
p.P(`i+=copy(dAtA[i:], 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(`i+=copy(dAtA[i:], m.XXX_unrecognized)`) |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
|
|
p.P(`return i, nil`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P() |
|
|
|
//Generate MarshalTo methods for oneof fields |
|
m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) |
|
for _, field := range m.Field { |
|
oneof := field.OneofIndex != nil |
|
if !oneof { |
|
continue |
|
} |
|
ccTypeName := p.OneOfTypeName(message, field) |
|
p.P(`func (m *`, ccTypeName, `) MarshalTo(dAtA []byte) (int, error) {`) |
|
p.In() |
|
p.P(`i := 0`) |
|
vanity.TurnOffNullableForNativeTypes(field) |
|
p.generateField(false, numGen, file, message, field) |
|
p.P(`return i, nil`) |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
|
|
if p.atleastOne { |
|
p.P(`func encodeVarint`, p.localName, `(dAtA []byte, offset int, v uint64) int {`) |
|
p.In() |
|
p.P(`for v >= 1<<7 {`) |
|
p.In() |
|
p.P(`dAtA[offset] = uint8(v&0x7f|0x80)`) |
|
p.P(`v >>= 7`) |
|
p.P(`offset++`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`dAtA[offset] = uint8(v)`) |
|
p.P(`return offset+1`) |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
|
|
} |
|
|
|
func init() { |
|
generator.RegisterPlugin(NewMarshal()) |
|
}
|
|
|