mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-17 19:08:46 -07:00
fa0101bd60
This changes the BEP protocol to use protocol buffer serialization instead of XDR, and therefore also the database format. The local discovery protocol is also updated to be protocol buffer format. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3276 LGTM: AudriusButkevicius
1326 lines
33 KiB
Go
1326 lines
33 KiB
Go
// Go support for Protocol Buffers - Google's data interchange format
|
|
//
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// https://github.com/golang/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.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// 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.
|
|
|
|
package proto
|
|
|
|
/*
|
|
* Routines for encoding data into the wire format for protocol buffers.
|
|
*/
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
)
|
|
|
|
// RequiredNotSetError is the error returned if Marshal is called with
|
|
// a protocol buffer struct whose required fields have not
|
|
// all been initialized. It is also the error returned if Unmarshal is
|
|
// called with an encoded protocol buffer that does not include all the
|
|
// required fields.
|
|
//
|
|
// When printed, RequiredNotSetError reports the first unset required field in a
|
|
// message. If the field cannot be precisely determined, it is reported as
|
|
// "{Unknown}".
|
|
type RequiredNotSetError struct {
|
|
field string
|
|
}
|
|
|
|
func (e *RequiredNotSetError) Error() string {
|
|
return fmt.Sprintf("proto: required field %q not set", e.field)
|
|
}
|
|
|
|
var (
|
|
// errRepeatedHasNil is the error returned if Marshal is called with
|
|
// a struct with a repeated field containing a nil element.
|
|
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
|
|
|
|
// ErrNil is the error returned if Marshal is called with nil.
|
|
ErrNil = errors.New("proto: Marshal called with nil")
|
|
)
|
|
|
|
// The fundamental encoders that put bytes on the wire.
|
|
// Those that take integer types all accept uint64 and are
|
|
// therefore of type valueEncoder.
|
|
|
|
const maxVarintBytes = 10 // maximum length of a varint
|
|
|
|
// EncodeVarint returns the varint encoding of x.
|
|
// This is the format for the
|
|
// int32, int64, uint32, uint64, bool, and enum
|
|
// protocol buffer types.
|
|
// Not used by the package itself, but helpful to clients
|
|
// wishing to use the same encoding.
|
|
func EncodeVarint(x uint64) []byte {
|
|
var buf [maxVarintBytes]byte
|
|
var n int
|
|
for n = 0; x > 127; n++ {
|
|
buf[n] = 0x80 | uint8(x&0x7F)
|
|
x >>= 7
|
|
}
|
|
buf[n] = uint8(x)
|
|
n++
|
|
return buf[0:n]
|
|
}
|
|
|
|
// EncodeVarint writes a varint-encoded integer to the Buffer.
|
|
// This is the format for the
|
|
// int32, int64, uint32, uint64, bool, and enum
|
|
// protocol buffer types.
|
|
func (p *Buffer) EncodeVarint(x uint64) error {
|
|
for x >= 1<<7 {
|
|
p.buf = append(p.buf, uint8(x&0x7f|0x80))
|
|
x >>= 7
|
|
}
|
|
p.buf = append(p.buf, uint8(x))
|
|
return nil
|
|
}
|
|
|
|
// SizeVarint returns the varint encoding size of an integer.
|
|
func SizeVarint(x uint64) int {
|
|
return sizeVarint(x)
|
|
}
|
|
|
|
func sizeVarint(x uint64) (n int) {
|
|
for {
|
|
n++
|
|
x >>= 7
|
|
if x == 0 {
|
|
break
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// EncodeFixed64 writes a 64-bit integer to the Buffer.
|
|
// This is the format for the
|
|
// fixed64, sfixed64, and double protocol buffer types.
|
|
func (p *Buffer) EncodeFixed64(x uint64) error {
|
|
p.buf = append(p.buf,
|
|
uint8(x),
|
|
uint8(x>>8),
|
|
uint8(x>>16),
|
|
uint8(x>>24),
|
|
uint8(x>>32),
|
|
uint8(x>>40),
|
|
uint8(x>>48),
|
|
uint8(x>>56))
|
|
return nil
|
|
}
|
|
|
|
func sizeFixed64(x uint64) int {
|
|
return 8
|
|
}
|
|
|
|
// EncodeFixed32 writes a 32-bit integer to the Buffer.
|
|
// This is the format for the
|
|
// fixed32, sfixed32, and float protocol buffer types.
|
|
func (p *Buffer) EncodeFixed32(x uint64) error {
|
|
p.buf = append(p.buf,
|
|
uint8(x),
|
|
uint8(x>>8),
|
|
uint8(x>>16),
|
|
uint8(x>>24))
|
|
return nil
|
|
}
|
|
|
|
func sizeFixed32(x uint64) int {
|
|
return 4
|
|
}
|
|
|
|
// EncodeZigzag64 writes a zigzag-encoded 64-bit integer
|
|
// to the Buffer.
|
|
// This is the format used for the sint64 protocol buffer type.
|
|
func (p *Buffer) EncodeZigzag64(x uint64) error {
|
|
// use signed number to get arithmetic right shift.
|
|
return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
|
}
|
|
|
|
func sizeZigzag64(x uint64) int {
|
|
return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
|
}
|
|
|
|
// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
|
|
// to the Buffer.
|
|
// This is the format used for the sint32 protocol buffer type.
|
|
func (p *Buffer) EncodeZigzag32(x uint64) error {
|
|
// use signed number to get arithmetic right shift.
|
|
return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
|
|
}
|
|
|
|
func sizeZigzag32(x uint64) int {
|
|
return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
|
|
}
|
|
|
|
// EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
|
|
// This is the format used for the bytes protocol buffer
|
|
// type and for embedded messages.
|
|
func (p *Buffer) EncodeRawBytes(b []byte) error {
|
|
p.EncodeVarint(uint64(len(b)))
|
|
p.buf = append(p.buf, b...)
|
|
return nil
|
|
}
|
|
|
|
func sizeRawBytes(b []byte) int {
|
|
return sizeVarint(uint64(len(b))) +
|
|
len(b)
|
|
}
|
|
|
|
// EncodeStringBytes writes an encoded string to the Buffer.
|
|
// This is the format used for the proto2 string type.
|
|
func (p *Buffer) EncodeStringBytes(s string) error {
|
|
p.EncodeVarint(uint64(len(s)))
|
|
p.buf = append(p.buf, s...)
|
|
return nil
|
|
}
|
|
|
|
func sizeStringBytes(s string) int {
|
|
return sizeVarint(uint64(len(s))) +
|
|
len(s)
|
|
}
|
|
|
|
// Marshaler is the interface representing objects that can marshal themselves.
|
|
type Marshaler interface {
|
|
Marshal() ([]byte, error)
|
|
}
|
|
|
|
// Marshal takes the protocol buffer
|
|
// and encodes it into the wire format, returning the data.
|
|
func Marshal(pb Message) ([]byte, error) {
|
|
// Can the object marshal itself?
|
|
if m, ok := pb.(Marshaler); ok {
|
|
return m.Marshal()
|
|
}
|
|
p := NewBuffer(nil)
|
|
err := p.Marshal(pb)
|
|
var state errorState
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
return nil, err
|
|
}
|
|
if p.buf == nil && err == nil {
|
|
// Return a non-nil slice on success.
|
|
return []byte{}, nil
|
|
}
|
|
return p.buf, err
|
|
}
|
|
|
|
// EncodeMessage writes the protocol buffer to the Buffer,
|
|
// prefixed by a varint-encoded length.
|
|
func (p *Buffer) EncodeMessage(pb Message) error {
|
|
t, base, err := getbase(pb)
|
|
if structPointer_IsNil(base) {
|
|
return ErrNil
|
|
}
|
|
if err == nil {
|
|
var state errorState
|
|
err = p.enc_len_struct(GetProperties(t.Elem()), base, &state)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Marshal takes the protocol buffer
|
|
// and encodes it into the wire format, writing the result to the
|
|
// Buffer.
|
|
func (p *Buffer) Marshal(pb Message) error {
|
|
// Can the object marshal itself?
|
|
if m, ok := pb.(Marshaler); ok {
|
|
data, err := m.Marshal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.buf = append(p.buf, data...)
|
|
return nil
|
|
}
|
|
|
|
t, base, err := getbase(pb)
|
|
if structPointer_IsNil(base) {
|
|
return ErrNil
|
|
}
|
|
if err == nil {
|
|
err = p.enc_struct(GetProperties(t.Elem()), base)
|
|
}
|
|
|
|
if collectStats {
|
|
stats.Encode++
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// Size returns the encoded size of a protocol buffer.
|
|
func Size(pb Message) (n int) {
|
|
// Can the object marshal itself? If so, Size is slow.
|
|
// TODO: add Size to Marshaler, or add a Sizer interface.
|
|
if m, ok := pb.(Marshaler); ok {
|
|
b, _ := m.Marshal()
|
|
return len(b)
|
|
}
|
|
|
|
t, base, err := getbase(pb)
|
|
if structPointer_IsNil(base) {
|
|
return 0
|
|
}
|
|
if err == nil {
|
|
n = size_struct(GetProperties(t.Elem()), base)
|
|
}
|
|
|
|
if collectStats {
|
|
stats.Size++
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Individual type encoders.
|
|
|
|
// Encode a bool.
|
|
func (o *Buffer) enc_bool(p *Properties, base structPointer) error {
|
|
v := *structPointer_Bool(base, p.field)
|
|
if v == nil {
|
|
return ErrNil
|
|
}
|
|
x := 0
|
|
if *v {
|
|
x = 1
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, uint64(x))
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error {
|
|
v := *structPointer_BoolVal(base, p.field)
|
|
if !v {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, 1)
|
|
return nil
|
|
}
|
|
|
|
func size_bool(p *Properties, base structPointer) int {
|
|
v := *structPointer_Bool(base, p.field)
|
|
if v == nil {
|
|
return 0
|
|
}
|
|
return len(p.tagcode) + 1 // each bool takes exactly one byte
|
|
}
|
|
|
|
func size_proto3_bool(p *Properties, base structPointer) int {
|
|
v := *structPointer_BoolVal(base, p.field)
|
|
if !v && !p.oneof {
|
|
return 0
|
|
}
|
|
return len(p.tagcode) + 1 // each bool takes exactly one byte
|
|
}
|
|
|
|
// Encode an int32.
|
|
func (o *Buffer) enc_int32(p *Properties, base structPointer) error {
|
|
v := structPointer_Word32(base, p.field)
|
|
if word32_IsNil(v) {
|
|
return ErrNil
|
|
}
|
|
x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, uint64(x))
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error {
|
|
v := structPointer_Word32Val(base, p.field)
|
|
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
|
|
if x == 0 {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, uint64(x))
|
|
return nil
|
|
}
|
|
|
|
func size_int32(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word32(base, p.field)
|
|
if word32_IsNil(v) {
|
|
return 0
|
|
}
|
|
x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range
|
|
n += len(p.tagcode)
|
|
n += p.valSize(uint64(x))
|
|
return
|
|
}
|
|
|
|
func size_proto3_int32(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word32Val(base, p.field)
|
|
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
|
|
if x == 0 && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += p.valSize(uint64(x))
|
|
return
|
|
}
|
|
|
|
// Encode a uint32.
|
|
// Exactly the same as int32, except for no sign extension.
|
|
func (o *Buffer) enc_uint32(p *Properties, base structPointer) error {
|
|
v := structPointer_Word32(base, p.field)
|
|
if word32_IsNil(v) {
|
|
return ErrNil
|
|
}
|
|
x := word32_Get(v)
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, uint64(x))
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error {
|
|
v := structPointer_Word32Val(base, p.field)
|
|
x := word32Val_Get(v)
|
|
if x == 0 {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, uint64(x))
|
|
return nil
|
|
}
|
|
|
|
func size_uint32(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word32(base, p.field)
|
|
if word32_IsNil(v) {
|
|
return 0
|
|
}
|
|
x := word32_Get(v)
|
|
n += len(p.tagcode)
|
|
n += p.valSize(uint64(x))
|
|
return
|
|
}
|
|
|
|
func size_proto3_uint32(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word32Val(base, p.field)
|
|
x := word32Val_Get(v)
|
|
if x == 0 && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += p.valSize(uint64(x))
|
|
return
|
|
}
|
|
|
|
// Encode an int64.
|
|
func (o *Buffer) enc_int64(p *Properties, base structPointer) error {
|
|
v := structPointer_Word64(base, p.field)
|
|
if word64_IsNil(v) {
|
|
return ErrNil
|
|
}
|
|
x := word64_Get(v)
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, x)
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error {
|
|
v := structPointer_Word64Val(base, p.field)
|
|
x := word64Val_Get(v)
|
|
if x == 0 {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, x)
|
|
return nil
|
|
}
|
|
|
|
func size_int64(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word64(base, p.field)
|
|
if word64_IsNil(v) {
|
|
return 0
|
|
}
|
|
x := word64_Get(v)
|
|
n += len(p.tagcode)
|
|
n += p.valSize(x)
|
|
return
|
|
}
|
|
|
|
func size_proto3_int64(p *Properties, base structPointer) (n int) {
|
|
v := structPointer_Word64Val(base, p.field)
|
|
x := word64Val_Get(v)
|
|
if x == 0 && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += p.valSize(x)
|
|
return
|
|
}
|
|
|
|
// Encode a string.
|
|
func (o *Buffer) enc_string(p *Properties, base structPointer) error {
|
|
v := *structPointer_String(base, p.field)
|
|
if v == nil {
|
|
return ErrNil
|
|
}
|
|
x := *v
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeStringBytes(x)
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error {
|
|
v := *structPointer_StringVal(base, p.field)
|
|
if v == "" {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeStringBytes(v)
|
|
return nil
|
|
}
|
|
|
|
func size_string(p *Properties, base structPointer) (n int) {
|
|
v := *structPointer_String(base, p.field)
|
|
if v == nil {
|
|
return 0
|
|
}
|
|
x := *v
|
|
n += len(p.tagcode)
|
|
n += sizeStringBytes(x)
|
|
return
|
|
}
|
|
|
|
func size_proto3_string(p *Properties, base structPointer) (n int) {
|
|
v := *structPointer_StringVal(base, p.field)
|
|
if v == "" && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += sizeStringBytes(v)
|
|
return
|
|
}
|
|
|
|
// All protocol buffer fields are nillable, but be careful.
|
|
func isNil(v reflect.Value) bool {
|
|
switch v.Kind() {
|
|
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
return v.IsNil()
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Encode a message struct.
|
|
func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
|
|
var state errorState
|
|
structp := structPointer_GetStructPointer(base, p.field)
|
|
if structPointer_IsNil(structp) {
|
|
return ErrNil
|
|
}
|
|
|
|
// Can the object marshal itself?
|
|
if p.isMarshaler {
|
|
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
|
data, err := m.Marshal()
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
return err
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeRawBytes(data)
|
|
return state.err
|
|
}
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
return o.enc_len_struct(p.sprop, structp, &state)
|
|
}
|
|
|
|
func size_struct_message(p *Properties, base structPointer) int {
|
|
structp := structPointer_GetStructPointer(base, p.field)
|
|
if structPointer_IsNil(structp) {
|
|
return 0
|
|
}
|
|
|
|
// Can the object marshal itself?
|
|
if p.isMarshaler {
|
|
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
|
data, _ := m.Marshal()
|
|
n0 := len(p.tagcode)
|
|
n1 := sizeRawBytes(data)
|
|
return n0 + n1
|
|
}
|
|
|
|
n0 := len(p.tagcode)
|
|
n1 := size_struct(p.sprop, structp)
|
|
n2 := sizeVarint(uint64(n1)) // size of encoded length
|
|
return n0 + n1 + n2
|
|
}
|
|
|
|
// Encode a group struct.
|
|
func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
|
|
var state errorState
|
|
b := structPointer_GetStructPointer(base, p.field)
|
|
if structPointer_IsNil(b) {
|
|
return ErrNil
|
|
}
|
|
|
|
o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
|
|
err := o.enc_struct(p.sprop, b)
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
return err
|
|
}
|
|
o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
|
|
return state.err
|
|
}
|
|
|
|
func size_struct_group(p *Properties, base structPointer) (n int) {
|
|
b := structPointer_GetStructPointer(base, p.field)
|
|
if structPointer_IsNil(b) {
|
|
return 0
|
|
}
|
|
|
|
n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup))
|
|
n += size_struct(p.sprop, b)
|
|
n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup))
|
|
return
|
|
}
|
|
|
|
// Encode a slice of bools ([]bool).
|
|
func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error {
|
|
s := *structPointer_BoolSlice(base, p.field)
|
|
l := len(s)
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
for _, x := range s {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
v := uint64(0)
|
|
if x {
|
|
v = 1
|
|
}
|
|
p.valEnc(o, v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_bool(p *Properties, base structPointer) int {
|
|
s := *structPointer_BoolSlice(base, p.field)
|
|
l := len(s)
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
return l * (len(p.tagcode) + 1) // each bool takes exactly one byte
|
|
}
|
|
|
|
// Encode a slice of bools ([]bool) in packed format.
|
|
func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error {
|
|
s := *structPointer_BoolSlice(base, p.field)
|
|
l := len(s)
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeVarint(uint64(l)) // each bool takes exactly one byte
|
|
for _, x := range s {
|
|
v := uint64(0)
|
|
if x {
|
|
v = 1
|
|
}
|
|
p.valEnc(o, v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_packed_bool(p *Properties, base structPointer) (n int) {
|
|
s := *structPointer_BoolSlice(base, p.field)
|
|
l := len(s)
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += sizeVarint(uint64(l))
|
|
n += l // each bool takes exactly one byte
|
|
return
|
|
}
|
|
|
|
// Encode a slice of bytes ([]byte).
|
|
func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error {
|
|
s := *structPointer_Bytes(base, p.field)
|
|
if s == nil {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeRawBytes(s)
|
|
return nil
|
|
}
|
|
|
|
func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error {
|
|
s := *structPointer_Bytes(base, p.field)
|
|
if len(s) == 0 {
|
|
return ErrNil
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeRawBytes(s)
|
|
return nil
|
|
}
|
|
|
|
func size_slice_byte(p *Properties, base structPointer) (n int) {
|
|
s := *structPointer_Bytes(base, p.field)
|
|
if s == nil && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += sizeRawBytes(s)
|
|
return
|
|
}
|
|
|
|
func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
|
|
s := *structPointer_Bytes(base, p.field)
|
|
if len(s) == 0 && !p.oneof {
|
|
return 0
|
|
}
|
|
n += len(p.tagcode)
|
|
n += sizeRawBytes(s)
|
|
return
|
|
}
|
|
|
|
// Encode a slice of int32s ([]int32).
|
|
func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
|
|
p.valEnc(o, uint64(x))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_int32(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
n += len(p.tagcode)
|
|
x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
|
|
n += p.valSize(uint64(x))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of int32s ([]int32) in packed format.
|
|
func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
// TODO: Reuse a Buffer.
|
|
buf := NewBuffer(nil)
|
|
for i := 0; i < l; i++ {
|
|
x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
|
|
p.valEnc(buf, uint64(x))
|
|
}
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeVarint(uint64(len(buf.buf)))
|
|
o.buf = append(o.buf, buf.buf...)
|
|
return nil
|
|
}
|
|
|
|
func size_slice_packed_int32(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
var bufSize int
|
|
for i := 0; i < l; i++ {
|
|
x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
|
|
bufSize += p.valSize(uint64(x))
|
|
}
|
|
|
|
n += len(p.tagcode)
|
|
n += sizeVarint(uint64(bufSize))
|
|
n += bufSize
|
|
return
|
|
}
|
|
|
|
// Encode a slice of uint32s ([]uint32).
|
|
// Exactly the same as int32, except for no sign extension.
|
|
func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
x := s.Index(i)
|
|
p.valEnc(o, uint64(x))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_uint32(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
n += len(p.tagcode)
|
|
x := s.Index(i)
|
|
n += p.valSize(uint64(x))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of uint32s ([]uint32) in packed format.
|
|
// Exactly the same as int32, except for no sign extension.
|
|
func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
// TODO: Reuse a Buffer.
|
|
buf := NewBuffer(nil)
|
|
for i := 0; i < l; i++ {
|
|
p.valEnc(buf, uint64(s.Index(i)))
|
|
}
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeVarint(uint64(len(buf.buf)))
|
|
o.buf = append(o.buf, buf.buf...)
|
|
return nil
|
|
}
|
|
|
|
func size_slice_packed_uint32(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word32Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
var bufSize int
|
|
for i := 0; i < l; i++ {
|
|
bufSize += p.valSize(uint64(s.Index(i)))
|
|
}
|
|
|
|
n += len(p.tagcode)
|
|
n += sizeVarint(uint64(bufSize))
|
|
n += bufSize
|
|
return
|
|
}
|
|
|
|
// Encode a slice of int64s ([]int64).
|
|
func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error {
|
|
s := structPointer_Word64Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
p.valEnc(o, s.Index(i))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_int64(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word64Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
n += len(p.tagcode)
|
|
n += p.valSize(s.Index(i))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of int64s ([]int64) in packed format.
|
|
func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error {
|
|
s := structPointer_Word64Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
// TODO: Reuse a Buffer.
|
|
buf := NewBuffer(nil)
|
|
for i := 0; i < l; i++ {
|
|
p.valEnc(buf, s.Index(i))
|
|
}
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeVarint(uint64(len(buf.buf)))
|
|
o.buf = append(o.buf, buf.buf...)
|
|
return nil
|
|
}
|
|
|
|
func size_slice_packed_int64(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_Word64Slice(base, p.field)
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
var bufSize int
|
|
for i := 0; i < l; i++ {
|
|
bufSize += p.valSize(s.Index(i))
|
|
}
|
|
|
|
n += len(p.tagcode)
|
|
n += sizeVarint(uint64(bufSize))
|
|
n += bufSize
|
|
return
|
|
}
|
|
|
|
// Encode a slice of slice of bytes ([][]byte).
|
|
func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error {
|
|
ss := *structPointer_BytesSlice(base, p.field)
|
|
l := len(ss)
|
|
if l == 0 {
|
|
return ErrNil
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeRawBytes(ss[i])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_slice_byte(p *Properties, base structPointer) (n int) {
|
|
ss := *structPointer_BytesSlice(base, p.field)
|
|
l := len(ss)
|
|
if l == 0 {
|
|
return 0
|
|
}
|
|
n += l * len(p.tagcode)
|
|
for i := 0; i < l; i++ {
|
|
n += sizeRawBytes(ss[i])
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of strings ([]string).
|
|
func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error {
|
|
ss := *structPointer_StringSlice(base, p.field)
|
|
l := len(ss)
|
|
for i := 0; i < l; i++ {
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeStringBytes(ss[i])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_slice_string(p *Properties, base structPointer) (n int) {
|
|
ss := *structPointer_StringSlice(base, p.field)
|
|
l := len(ss)
|
|
n += l * len(p.tagcode)
|
|
for i := 0; i < l; i++ {
|
|
n += sizeStringBytes(ss[i])
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of message structs ([]*struct).
|
|
func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error {
|
|
var state errorState
|
|
s := structPointer_StructPointerSlice(base, p.field)
|
|
l := s.Len()
|
|
|
|
for i := 0; i < l; i++ {
|
|
structp := s.Index(i)
|
|
if structPointer_IsNil(structp) {
|
|
return errRepeatedHasNil
|
|
}
|
|
|
|
// Can the object marshal itself?
|
|
if p.isMarshaler {
|
|
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
|
data, err := m.Marshal()
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
return err
|
|
}
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
o.EncodeRawBytes(data)
|
|
continue
|
|
}
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
err := o.enc_len_struct(p.sprop, structp, &state)
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
if err == ErrNil {
|
|
return errRepeatedHasNil
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
return state.err
|
|
}
|
|
|
|
func size_slice_struct_message(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_StructPointerSlice(base, p.field)
|
|
l := s.Len()
|
|
n += l * len(p.tagcode)
|
|
for i := 0; i < l; i++ {
|
|
structp := s.Index(i)
|
|
if structPointer_IsNil(structp) {
|
|
return // return the size up to this point
|
|
}
|
|
|
|
// Can the object marshal itself?
|
|
if p.isMarshaler {
|
|
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
|
data, _ := m.Marshal()
|
|
n += len(p.tagcode)
|
|
n += sizeRawBytes(data)
|
|
continue
|
|
}
|
|
|
|
n0 := size_struct(p.sprop, structp)
|
|
n1 := sizeVarint(uint64(n0)) // size of encoded length
|
|
n += n0 + n1
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a slice of group structs ([]*struct).
|
|
func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error {
|
|
var state errorState
|
|
s := structPointer_StructPointerSlice(base, p.field)
|
|
l := s.Len()
|
|
|
|
for i := 0; i < l; i++ {
|
|
b := s.Index(i)
|
|
if structPointer_IsNil(b) {
|
|
return errRepeatedHasNil
|
|
}
|
|
|
|
o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
|
|
|
|
err := o.enc_struct(p.sprop, b)
|
|
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
if err == ErrNil {
|
|
return errRepeatedHasNil
|
|
}
|
|
return err
|
|
}
|
|
|
|
o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
|
|
}
|
|
return state.err
|
|
}
|
|
|
|
func size_slice_struct_group(p *Properties, base structPointer) (n int) {
|
|
s := structPointer_StructPointerSlice(base, p.field)
|
|
l := s.Len()
|
|
|
|
n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup))
|
|
n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup))
|
|
for i := 0; i < l; i++ {
|
|
b := s.Index(i)
|
|
if structPointer_IsNil(b) {
|
|
return // return size up to this point
|
|
}
|
|
|
|
n += size_struct(p.sprop, b)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode an extension map.
|
|
func (o *Buffer) enc_map(p *Properties, base structPointer) error {
|
|
v := *structPointer_ExtMap(base, p.field)
|
|
if err := encodeExtensionMap(v); err != nil {
|
|
return err
|
|
}
|
|
// Fast-path for common cases: zero or one extensions.
|
|
if len(v) <= 1 {
|
|
for _, e := range v {
|
|
o.buf = append(o.buf, e.enc...)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Sort keys to provide a deterministic encoding.
|
|
keys := make([]int, 0, len(v))
|
|
for k := range v {
|
|
keys = append(keys, int(k))
|
|
}
|
|
sort.Ints(keys)
|
|
|
|
for _, k := range keys {
|
|
o.buf = append(o.buf, v[int32(k)].enc...)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_map(p *Properties, base structPointer) int {
|
|
v := *structPointer_ExtMap(base, p.field)
|
|
return sizeExtensionMap(v)
|
|
}
|
|
|
|
// Encode a map field.
|
|
func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
|
|
var state errorState // XXX: or do we need to plumb this through?
|
|
|
|
/*
|
|
A map defined as
|
|
map<key_type, value_type> map_field = N;
|
|
is encoded in the same way as
|
|
message MapFieldEntry {
|
|
key_type key = 1;
|
|
value_type value = 2;
|
|
}
|
|
repeated MapFieldEntry map_field = N;
|
|
*/
|
|
|
|
v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
|
|
if v.Len() == 0 {
|
|
return nil
|
|
}
|
|
|
|
keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
|
|
|
|
enc := func() error {
|
|
if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil {
|
|
return err
|
|
}
|
|
if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Don't sort map keys. It is not required by the spec, and C++ doesn't do it.
|
|
for _, key := range v.MapKeys() {
|
|
val := v.MapIndex(key)
|
|
|
|
// The only illegal map entry values are nil message pointers.
|
|
if val.Kind() == reflect.Ptr && val.IsNil() {
|
|
return errors.New("proto: map has nil element")
|
|
}
|
|
|
|
keycopy.Set(key)
|
|
valcopy.Set(val)
|
|
|
|
o.buf = append(o.buf, p.tagcode...)
|
|
if err := o.enc_len_thing(enc, &state); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func size_new_map(p *Properties, base structPointer) int {
|
|
v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
|
|
|
|
keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
|
|
|
|
n := 0
|
|
for _, key := range v.MapKeys() {
|
|
val := v.MapIndex(key)
|
|
keycopy.Set(key)
|
|
valcopy.Set(val)
|
|
|
|
// Tag codes for key and val are the responsibility of the sub-sizer.
|
|
keysize := p.mkeyprop.size(p.mkeyprop, keybase)
|
|
valsize := p.mvalprop.size(p.mvalprop, valbase)
|
|
entry := keysize + valsize
|
|
// Add on tag code and length of map entry itself.
|
|
n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry
|
|
}
|
|
return n
|
|
}
|
|
|
|
// mapEncodeScratch returns a new reflect.Value matching the map's value type,
|
|
// and a structPointer suitable for passing to an encoder or sizer.
|
|
func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) {
|
|
// Prepare addressable doubly-indirect placeholders for the key and value types.
|
|
// This is needed because the element-type encoders expect **T, but the map iteration produces T.
|
|
|
|
keycopy = reflect.New(mapType.Key()).Elem() // addressable K
|
|
keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K
|
|
keyptr.Set(keycopy.Addr()) //
|
|
keybase = toStructPointer(keyptr.Addr()) // **K
|
|
|
|
// Value types are more varied and require special handling.
|
|
switch mapType.Elem().Kind() {
|
|
case reflect.Slice:
|
|
// []byte
|
|
var dummy []byte
|
|
valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte
|
|
valbase = toStructPointer(valcopy.Addr())
|
|
case reflect.Ptr:
|
|
// message; the generated field type is map[K]*Msg (so V is *Msg),
|
|
// so we only need one level of indirection.
|
|
valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
|
|
valbase = toStructPointer(valcopy.Addr())
|
|
default:
|
|
// everything else
|
|
valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
|
|
valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V
|
|
valptr.Set(valcopy.Addr()) //
|
|
valbase = toStructPointer(valptr.Addr()) // **V
|
|
}
|
|
return
|
|
}
|
|
|
|
// Encode a struct.
|
|
func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
|
|
var state errorState
|
|
// Encode fields in tag order so that decoders may use optimizations
|
|
// that depend on the ordering.
|
|
// https://developers.google.com/protocol-buffers/docs/encoding#order
|
|
for _, i := range prop.order {
|
|
p := prop.Prop[i]
|
|
if p.enc != nil {
|
|
err := p.enc(o, p, base)
|
|
if err != nil {
|
|
if err == ErrNil {
|
|
if p.Required && state.err == nil {
|
|
state.err = &RequiredNotSetError{p.Name}
|
|
}
|
|
} else if err == errRepeatedHasNil {
|
|
// Give more context to nil values in repeated fields.
|
|
return errors.New("repeated field " + p.OrigName + " has nil element")
|
|
} else if !state.shouldContinue(err, p) {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do oneof fields.
|
|
if prop.oneofMarshaler != nil {
|
|
m := structPointer_Interface(base, prop.stype).(Message)
|
|
if err := prop.oneofMarshaler(m, o); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Add unrecognized fields at the end.
|
|
if prop.unrecField.IsValid() {
|
|
v := *structPointer_Bytes(base, prop.unrecField)
|
|
if len(v) > 0 {
|
|
o.buf = append(o.buf, v...)
|
|
}
|
|
}
|
|
|
|
return state.err
|
|
}
|
|
|
|
func size_struct(prop *StructProperties, base structPointer) (n int) {
|
|
for _, i := range prop.order {
|
|
p := prop.Prop[i]
|
|
if p.size != nil {
|
|
n += p.size(p, base)
|
|
}
|
|
}
|
|
|
|
// Add unrecognized fields at the end.
|
|
if prop.unrecField.IsValid() {
|
|
v := *structPointer_Bytes(base, prop.unrecField)
|
|
n += len(v)
|
|
}
|
|
|
|
// Factor in any oneof fields.
|
|
if prop.oneofSizer != nil {
|
|
m := structPointer_Interface(base, prop.stype).(Message)
|
|
n += prop.oneofSizer(m)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
var zeroes [20]byte // longer than any conceivable sizeVarint
|
|
|
|
// Encode a struct, preceded by its encoded length (as a varint).
|
|
func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error {
|
|
return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state)
|
|
}
|
|
|
|
// Encode something, preceded by its encoded length (as a varint).
|
|
func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error {
|
|
iLen := len(o.buf)
|
|
o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length
|
|
iMsg := len(o.buf)
|
|
err := enc()
|
|
if err != nil && !state.shouldContinue(err, nil) {
|
|
return err
|
|
}
|
|
lMsg := len(o.buf) - iMsg
|
|
lLen := sizeVarint(uint64(lMsg))
|
|
switch x := lLen - (iMsg - iLen); {
|
|
case x > 0: // actual length is x bytes larger than the space we reserved
|
|
// Move msg x bytes right.
|
|
o.buf = append(o.buf, zeroes[:x]...)
|
|
copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg])
|
|
case x < 0: // actual length is x bytes smaller than the space we reserved
|
|
// Move msg x bytes left.
|
|
copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg])
|
|
o.buf = o.buf[:len(o.buf)+x] // x is negative
|
|
}
|
|
// Encode the length in the reserved space.
|
|
o.buf = o.buf[:iLen]
|
|
o.EncodeVarint(uint64(lMsg))
|
|
o.buf = o.buf[:len(o.buf)+lMsg]
|
|
return state.err
|
|
}
|
|
|
|
// errorState maintains the first error that occurs and updates that error
|
|
// with additional context.
|
|
type errorState struct {
|
|
err error
|
|
}
|
|
|
|
// shouldContinue reports whether encoding should continue upon encountering the
|
|
// given error. If the error is RequiredNotSetError, shouldContinue returns true
|
|
// and, if this is the first appearance of that error, remembers it for future
|
|
// reporting.
|
|
//
|
|
// If prop is not nil, it may update any error with additional context about the
|
|
// field with the error.
|
|
func (s *errorState) shouldContinue(err error, prop *Properties) bool {
|
|
// Ignore unset required fields.
|
|
reqNotSet, ok := err.(*RequiredNotSetError)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if s.err == nil {
|
|
if prop != nil {
|
|
err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field}
|
|
}
|
|
s.err = err
|
|
}
|
|
return true
|
|
}
|