Roger
5 years ago
26 changed files with 11841 additions and 29 deletions
-
3.gitignore
-
2examples/zinx_version_ex/protoDemo/main.go
-
5go.mod
-
2go.sum
-
3vendor/github.com/golang/protobuf/AUTHORS
-
3vendor/github.com/golang/protobuf/CONTRIBUTORS
-
28vendor/github.com/golang/protobuf/LICENSE
-
253vendor/github.com/golang/protobuf/proto/clone.go
-
427vendor/github.com/golang/protobuf/proto/decode.go
-
63vendor/github.com/golang/protobuf/proto/deprecated.go
-
350vendor/github.com/golang/protobuf/proto/discard.go
-
203vendor/github.com/golang/protobuf/proto/encode.go
-
301vendor/github.com/golang/protobuf/proto/equal.go
-
607vendor/github.com/golang/protobuf/proto/extensions.go
-
965vendor/github.com/golang/protobuf/proto/lib.go
-
181vendor/github.com/golang/protobuf/proto/message_set.go
-
360vendor/github.com/golang/protobuf/proto/pointer_reflect.go
-
313vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
-
544vendor/github.com/golang/protobuf/proto/properties.go
-
2776vendor/github.com/golang/protobuf/proto/table_marshal.go
-
654vendor/github.com/golang/protobuf/proto/table_merge.go
-
2053vendor/github.com/golang/protobuf/proto/table_unmarshal.go
-
845vendor/github.com/golang/protobuf/proto/text.go
-
880vendor/github.com/golang/protobuf/proto/text_parser.go
-
2vendor/modules.txt
-
47zinx_app_demo/mmo_game/core/aoi.go
@ -0,0 +1,3 @@ |
|||
.idea |
|||
/zinx_app_demo/mmo_game/game_client/client_Data/ |
|||
/zinx_app_demt/mmo_game/mmo_game_log/ |
@ -0,0 +1,5 @@ |
|||
module zinx |
|||
|
|||
go 1.13 |
|||
|
|||
require github.com/golang/protobuf v1.3.3 |
@ -0,0 +1,2 @@ |
|||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= |
|||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |
@ -0,0 +1,3 @@ |
|||
# This source code refers to The Go Authors for copyright purposes. |
|||
# The master list of authors is in the main Go distribution, |
|||
# visible at http://tip.golang.org/AUTHORS. |
@ -0,0 +1,3 @@ |
|||
# This source code was written by the Go contributors. |
|||
# The master list of contributors is in the main Go distribution, |
|||
# visible at http://tip.golang.org/CONTRIBUTORS. |
@ -0,0 +1,28 @@ |
|||
Copyright 2010 The Go Authors. All rights reserved. |
|||
|
|||
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. |
|||
|
@ -0,0 +1,253 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2011 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.
|
|||
|
|||
// Protocol buffer deep copy and merge.
|
|||
// TODO: RawMessage.
|
|||
|
|||
package proto |
|||
|
|||
import ( |
|||
"fmt" |
|||
"log" |
|||
"reflect" |
|||
"strings" |
|||
) |
|||
|
|||
// Clone returns a deep copy of a protocol buffer.
|
|||
func Clone(src Message) Message { |
|||
in := reflect.ValueOf(src) |
|||
if in.IsNil() { |
|||
return src |
|||
} |
|||
out := reflect.New(in.Type().Elem()) |
|||
dst := out.Interface().(Message) |
|||
Merge(dst, src) |
|||
return dst |
|||
} |
|||
|
|||
// Merger is the interface representing objects that can merge messages of the same type.
|
|||
type Merger interface { |
|||
// Merge merges src into this message.
|
|||
// Required and optional fields that are set in src will be set to that value in dst.
|
|||
// Elements of repeated fields will be appended.
|
|||
//
|
|||
// Merge may panic if called with a different argument type than the receiver.
|
|||
Merge(src Message) |
|||
} |
|||
|
|||
// generatedMerger is the custom merge method that generated protos will have.
|
|||
// We must add this method since a generate Merge method will conflict with
|
|||
// many existing protos that have a Merge data field already defined.
|
|||
type generatedMerger interface { |
|||
XXX_Merge(src Message) |
|||
} |
|||
|
|||
// Merge merges src into dst.
|
|||
// Required and optional fields that are set in src will be set to that value in dst.
|
|||
// Elements of repeated fields will be appended.
|
|||
// Merge panics if src and dst are not the same type, or if dst is nil.
|
|||
func Merge(dst, src Message) { |
|||
if m, ok := dst.(Merger); ok { |
|||
m.Merge(src) |
|||
return |
|||
} |
|||
|
|||
in := reflect.ValueOf(src) |
|||
out := reflect.ValueOf(dst) |
|||
if out.IsNil() { |
|||
panic("proto: nil destination") |
|||
} |
|||
if in.Type() != out.Type() { |
|||
panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) |
|||
} |
|||
if in.IsNil() { |
|||
return // Merge from nil src is a noop
|
|||
} |
|||
if m, ok := dst.(generatedMerger); ok { |
|||
m.XXX_Merge(src) |
|||
return |
|||
} |
|||
mergeStruct(out.Elem(), in.Elem()) |
|||
} |
|||
|
|||
func mergeStruct(out, in reflect.Value) { |
|||
sprop := GetProperties(in.Type()) |
|||
for i := 0; i < in.NumField(); i++ { |
|||
f := in.Type().Field(i) |
|||
if strings.HasPrefix(f.Name, "XXX_") { |
|||
continue |
|||
} |
|||
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) |
|||
} |
|||
|
|||
if emIn, err := extendable(in.Addr().Interface()); err == nil { |
|||
emOut, _ := extendable(out.Addr().Interface()) |
|||
mIn, muIn := emIn.extensionsRead() |
|||
if mIn != nil { |
|||
mOut := emOut.extensionsWrite() |
|||
muIn.Lock() |
|||
mergeExtension(mOut, mIn) |
|||
muIn.Unlock() |
|||
} |
|||
} |
|||
|
|||
uf := in.FieldByName("XXX_unrecognized") |
|||
if !uf.IsValid() { |
|||
return |
|||
} |
|||
uin := uf.Bytes() |
|||
if len(uin) > 0 { |
|||
out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) |
|||
} |
|||
} |
|||
|
|||
// mergeAny performs a merge between two values of the same type.
|
|||
// viaPtr indicates whether the values were indirected through a pointer (implying proto2).
|
|||
// prop is set if this is a struct field (it may be nil).
|
|||
func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { |
|||
if in.Type() == protoMessageType { |
|||
if !in.IsNil() { |
|||
if out.IsNil() { |
|||
out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) |
|||
} else { |
|||
Merge(out.Interface().(Message), in.Interface().(Message)) |
|||
} |
|||
} |
|||
return |
|||
} |
|||
switch in.Kind() { |
|||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, |
|||
reflect.String, reflect.Uint32, reflect.Uint64: |
|||
if !viaPtr && isProto3Zero(in) { |
|||
return |
|||
} |
|||
out.Set(in) |
|||
case reflect.Interface: |
|||
// Probably a oneof field; copy non-nil values.
|
|||
if in.IsNil() { |
|||
return |
|||
} |
|||
// Allocate destination if it is not set, or set to a different type.
|
|||
// Otherwise we will merge as normal.
|
|||
if out.IsNil() || out.Elem().Type() != in.Elem().Type() { |
|||
out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
|
|||
} |
|||
mergeAny(out.Elem(), in.Elem(), false, nil) |
|||
case reflect.Map: |
|||
if in.Len() == 0 { |
|||
return |
|||
} |
|||
if out.IsNil() { |
|||
out.Set(reflect.MakeMap(in.Type())) |
|||
} |
|||
// For maps with value types of *T or []byte we need to deep copy each value.
|
|||
elemKind := in.Type().Elem().Kind() |
|||
for _, key := range in.MapKeys() { |
|||
var val reflect.Value |
|||
switch elemKind { |
|||
case reflect.Ptr: |
|||
val = reflect.New(in.Type().Elem().Elem()) |
|||
mergeAny(val, in.MapIndex(key), false, nil) |
|||
case reflect.Slice: |
|||
val = in.MapIndex(key) |
|||
val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) |
|||
default: |
|||
val = in.MapIndex(key) |
|||
} |
|||
out.SetMapIndex(key, val) |
|||
} |
|||
case reflect.Ptr: |
|||
if in.IsNil() { |
|||
return |
|||
} |
|||
if out.IsNil() { |
|||
out.Set(reflect.New(in.Elem().Type())) |
|||
} |
|||
mergeAny(out.Elem(), in.Elem(), true, nil) |
|||
case reflect.Slice: |
|||
if in.IsNil() { |
|||
return |
|||
} |
|||
if in.Type().Elem().Kind() == reflect.Uint8 { |
|||
// []byte is a scalar bytes field, not a repeated field.
|
|||
|
|||
// Edge case: if this is in a proto3 message, a zero length
|
|||
// bytes field is considered the zero value, and should not
|
|||
// be merged.
|
|||
if prop != nil && prop.proto3 && in.Len() == 0 { |
|||
return |
|||
} |
|||
|
|||
// Make a deep copy.
|
|||
// Append to []byte{} instead of []byte(nil) so that we never end up
|
|||
// with a nil result.
|
|||
out.SetBytes(append([]byte{}, in.Bytes()...)) |
|||
return |
|||
} |
|||
n := in.Len() |
|||
if out.IsNil() { |
|||
out.Set(reflect.MakeSlice(in.Type(), 0, n)) |
|||
} |
|||
switch in.Type().Elem().Kind() { |
|||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, |
|||
reflect.String, reflect.Uint32, reflect.Uint64: |
|||
out.Set(reflect.AppendSlice(out, in)) |
|||
default: |
|||
for i := 0; i < n; i++ { |
|||
x := reflect.Indirect(reflect.New(in.Type().Elem())) |
|||
mergeAny(x, in.Index(i), false, nil) |
|||
out.Set(reflect.Append(out, x)) |
|||
} |
|||
} |
|||
case reflect.Struct: |
|||
mergeStruct(out, in) |
|||
default: |
|||
// unknown type, so not a protocol buffer
|
|||
log.Printf("proto: don't know how to copy %v", in) |
|||
} |
|||
} |
|||
|
|||
func mergeExtension(out, in map[int32]Extension) { |
|||
for extNum, eIn := range in { |
|||
eOut := Extension{desc: eIn.desc} |
|||
if eIn.value != nil { |
|||
v := reflect.New(reflect.TypeOf(eIn.value)).Elem() |
|||
mergeAny(v, reflect.ValueOf(eIn.value), false, nil) |
|||
eOut.value = v.Interface() |
|||
} |
|||
if eIn.enc != nil { |
|||
eOut.enc = make([]byte, len(eIn.enc)) |
|||
copy(eOut.enc, eIn.enc) |
|||
} |
|||
|
|||
out[extNum] = eOut |
|||
} |
|||
} |
@ -0,0 +1,427 @@ |
|||
// 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 decoding protocol buffer data to construct in-memory representations. |
|||
*/ |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"io" |
|||
) |
|||
|
|||
// errOverflow is returned when an integer is too large to be represented.
|
|||
var errOverflow = errors.New("proto: integer overflow") |
|||
|
|||
// ErrInternalBadWireType is returned by generated code when an incorrect
|
|||
// wire type is encountered. It does not get returned to user code.
|
|||
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") |
|||
|
|||
// DecodeVarint reads a varint-encoded integer from the slice.
|
|||
// It returns the integer and the number of bytes consumed, or
|
|||
// zero if there is not enough.
|
|||
// This is the format for the
|
|||
// int32, int64, uint32, uint64, bool, and enum
|
|||
// protocol buffer types.
|
|||
func DecodeVarint(buf []byte) (x uint64, n int) { |
|||
for shift := uint(0); shift < 64; shift += 7 { |
|||
if n >= len(buf) { |
|||
return 0, 0 |
|||
} |
|||
b := uint64(buf[n]) |
|||
n++ |
|||
x |= (b & 0x7F) << shift |
|||
if (b & 0x80) == 0 { |
|||
return x, n |
|||
} |
|||
} |
|||
|
|||
// The number is too large to represent in a 64-bit value.
|
|||
return 0, 0 |
|||
} |
|||
|
|||
func (p *Buffer) decodeVarintSlow() (x uint64, err error) { |
|||
i := p.index |
|||
l := len(p.buf) |
|||
|
|||
for shift := uint(0); shift < 64; shift += 7 { |
|||
if i >= l { |
|||
err = io.ErrUnexpectedEOF |
|||
return |
|||
} |
|||
b := p.buf[i] |
|||
i++ |
|||
x |= (uint64(b) & 0x7F) << shift |
|||
if b < 0x80 { |
|||
p.index = i |
|||
return |
|||
} |
|||
} |
|||
|
|||
// The number is too large to represent in a 64-bit value.
|
|||
err = errOverflow |
|||
return |
|||
} |
|||
|
|||
// DecodeVarint reads a varint-encoded integer from the Buffer.
|
|||
// This is the format for the
|
|||
// int32, int64, uint32, uint64, bool, and enum
|
|||
// protocol buffer types.
|
|||
func (p *Buffer) DecodeVarint() (x uint64, err error) { |
|||
i := p.index |
|||
buf := p.buf |
|||
|
|||
if i >= len(buf) { |
|||
return 0, io.ErrUnexpectedEOF |
|||
} else if buf[i] < 0x80 { |
|||
p.index++ |
|||
return uint64(buf[i]), nil |
|||
} else if len(buf)-i < 10 { |
|||
return p.decodeVarintSlow() |
|||
} |
|||
|
|||
var b uint64 |
|||
// we already checked the first byte
|
|||
x = uint64(buf[i]) - 0x80 |
|||
i++ |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 7 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 7 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 14 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 14 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 21 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 21 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 28 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 28 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 35 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 35 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 42 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 42 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 49 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 49 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 56 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
x -= 0x80 << 56 |
|||
|
|||
b = uint64(buf[i]) |
|||
i++ |
|||
x += b << 63 |
|||
if b&0x80 == 0 { |
|||
goto done |
|||
} |
|||
|
|||
return 0, errOverflow |
|||
|
|||
done: |
|||
p.index = i |
|||
return x, nil |
|||
} |
|||
|
|||
// DecodeFixed64 reads a 64-bit integer from the Buffer.
|
|||
// This is the format for the
|
|||
// fixed64, sfixed64, and double protocol buffer types.
|
|||
func (p *Buffer) DecodeFixed64() (x uint64, err error) { |
|||
// x, err already 0
|
|||
i := p.index + 8 |
|||
if i < 0 || i > len(p.buf) { |
|||
err = io.ErrUnexpectedEOF |
|||
return |
|||
} |
|||
p.index = i |
|||
|
|||
x = uint64(p.buf[i-8]) |
|||
x |= uint64(p.buf[i-7]) << 8 |
|||
x |= uint64(p.buf[i-6]) << 16 |
|||
x |= uint64(p.buf[i-5]) << 24 |
|||
x |= uint64(p.buf[i-4]) << 32 |
|||
x |= uint64(p.buf[i-3]) << 40 |
|||
x |= uint64(p.buf[i-2]) << 48 |
|||
x |= uint64(p.buf[i-1]) << 56 |
|||
return |
|||
} |
|||
|
|||
// DecodeFixed32 reads a 32-bit integer from the Buffer.
|
|||
// This is the format for the
|
|||
// fixed32, sfixed32, and float protocol buffer types.
|
|||
func (p *Buffer) DecodeFixed32() (x uint64, err error) { |
|||
// x, err already 0
|
|||
i := p.index + 4 |
|||
if i < 0 || i > len(p.buf) { |
|||
err = io.ErrUnexpectedEOF |
|||
return |
|||
} |
|||
p.index = i |
|||
|
|||
x = uint64(p.buf[i-4]) |
|||
x |= uint64(p.buf[i-3]) << 8 |
|||
x |= uint64(p.buf[i-2]) << 16 |
|||
x |= uint64(p.buf[i-1]) << 24 |
|||
return |
|||
} |
|||
|
|||
// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
|
|||
// from the Buffer.
|
|||
// This is the format used for the sint64 protocol buffer type.
|
|||
func (p *Buffer) DecodeZigzag64() (x uint64, err error) { |
|||
x, err = p.DecodeVarint() |
|||
if err != nil { |
|||
return |
|||
} |
|||
x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) |
|||
return |
|||
} |
|||
|
|||
// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
|
|||
// from the Buffer.
|
|||
// This is the format used for the sint32 protocol buffer type.
|
|||
func (p *Buffer) DecodeZigzag32() (x uint64, err error) { |
|||
x, err = p.DecodeVarint() |
|||
if err != nil { |
|||
return |
|||
} |
|||
x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) |
|||
return |
|||
} |
|||
|
|||
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
|
|||
// This is the format used for the bytes protocol buffer
|
|||
// type and for embedded messages.
|
|||
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { |
|||
n, err := p.DecodeVarint() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
nb := int(n) |
|||
if nb < 0 { |
|||
return nil, fmt.Errorf("proto: bad byte length %d", nb) |
|||
} |
|||
end := p.index + nb |
|||
if end < p.index || end > len(p.buf) { |
|||
return nil, io.ErrUnexpectedEOF |
|||
} |
|||
|
|||
if !alloc { |
|||
// todo: check if can get more uses of alloc=false
|
|||
buf = p.buf[p.index:end] |
|||
p.index += nb |
|||
return |
|||
} |
|||
|
|||
buf = make([]byte, nb) |
|||
copy(buf, p.buf[p.index:]) |
|||
p.index += nb |
|||
return |
|||
} |
|||
|
|||
// DecodeStringBytes reads an encoded string from the Buffer.
|
|||
// This is the format used for the proto2 string type.
|
|||
func (p *Buffer) DecodeStringBytes() (s string, err error) { |
|||
buf, err := p.DecodeRawBytes(false) |
|||
if err != nil { |
|||
return |
|||
} |
|||
return string(buf), nil |
|||
} |
|||
|
|||
// Unmarshaler is the interface representing objects that can
|
|||
// unmarshal themselves. The argument points to data that may be
|
|||
// overwritten, so implementations should not keep references to the
|
|||
// buffer.
|
|||
// Unmarshal implementations should not clear the receiver.
|
|||
// Any unmarshaled data should be merged into the receiver.
|
|||
// Callers of Unmarshal that do not want to retain existing data
|
|||
// should Reset the receiver before calling Unmarshal.
|
|||
type Unmarshaler interface { |
|||
Unmarshal([]byte) error |
|||
} |
|||
|
|||
// newUnmarshaler is the interface representing objects that can
|
|||
// unmarshal themselves. The semantics are identical to Unmarshaler.
|
|||
//
|
|||
// This exists to support protoc-gen-go generated messages.
|
|||
// The proto package will stop type-asserting to this interface in the future.
|
|||
//
|
|||
// DO NOT DEPEND ON THIS.
|
|||
type newUnmarshaler interface { |
|||
XXX_Unmarshal([]byte) error |
|||
} |
|||
|
|||
// Unmarshal parses the protocol buffer representation in buf and places the
|
|||
// decoded result in pb. If the struct underlying pb does not match
|
|||
// the data in buf, the results can be unpredictable.
|
|||
//
|
|||
// Unmarshal resets pb before starting to unmarshal, so any
|
|||
// existing data in pb is always removed. Use UnmarshalMerge
|
|||
// to preserve and append to existing data.
|
|||
func Unmarshal(buf []byte, pb Message) error { |
|||
pb.Reset() |
|||
if u, ok := pb.(newUnmarshaler); ok { |
|||
return u.XXX_Unmarshal(buf) |
|||
} |
|||
if u, ok := pb.(Unmarshaler); ok { |
|||
return u.Unmarshal(buf) |
|||
} |
|||
return NewBuffer(buf).Unmarshal(pb) |
|||
} |
|||
|
|||
// UnmarshalMerge parses the protocol buffer representation in buf and
|
|||
// writes the decoded result to pb. If the struct underlying pb does not match
|
|||
// the data in buf, the results can be unpredictable.
|
|||
//
|
|||
// UnmarshalMerge merges into existing data in pb.
|
|||
// Most code should use Unmarshal instead.
|
|||
func UnmarshalMerge(buf []byte, pb Message) error { |
|||
if u, ok := pb.(newUnmarshaler); ok { |
|||
return u.XXX_Unmarshal(buf) |
|||
} |
|||
if u, ok := pb.(Unmarshaler); ok { |
|||
// NOTE: The history of proto have unfortunately been inconsistent
|
|||
// whether Unmarshaler should or should not implicitly clear itself.
|
|||
// Some implementations do, most do not.
|
|||
// Thus, calling this here may or may not do what people want.
|
|||
//
|
|||
// See https://github.com/golang/protobuf/issues/424
|
|||
return u.Unmarshal(buf) |
|||
} |
|||
return NewBuffer(buf).Unmarshal(pb) |
|||
} |
|||
|
|||
// DecodeMessage reads a count-delimited message from the Buffer.
|
|||
func (p *Buffer) DecodeMessage(pb Message) error { |
|||
enc, err := p.DecodeRawBytes(false) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
return NewBuffer(enc).Unmarshal(pb) |
|||
} |
|||
|
|||
// DecodeGroup reads a tag-delimited group from the Buffer.
|
|||
// StartGroup tag is already consumed. This function consumes
|
|||
// EndGroup tag.
|
|||
func (p *Buffer) DecodeGroup(pb Message) error { |
|||
b := p.buf[p.index:] |
|||
x, y := findEndGroup(b) |
|||
if x < 0 { |
|||
return io.ErrUnexpectedEOF |
|||
} |
|||
err := Unmarshal(b[:x], pb) |
|||
p.index += y |
|||
return err |
|||
} |
|||
|
|||
// Unmarshal parses the protocol buffer representation in the
|
|||
// Buffer and places the decoded result in pb. If the struct
|
|||
// underlying pb does not match the data in the buffer, the results can be
|
|||
// unpredictable.
|
|||
//
|
|||
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
|
|||
func (p *Buffer) Unmarshal(pb Message) error { |
|||
// If the object can unmarshal itself, let it.
|
|||
if u, ok := pb.(newUnmarshaler); ok { |
|||
err := u.XXX_Unmarshal(p.buf[p.index:]) |
|||
p.index = len(p.buf) |
|||
return err |
|||
} |
|||
if u, ok := pb.(Unmarshaler); ok { |
|||
// NOTE: The history of proto have unfortunately been inconsistent
|
|||
// whether Unmarshaler should or should not implicitly clear itself.
|
|||
// Some implementations do, most do not.
|
|||
// Thus, calling this here may or may not do what people want.
|
|||
//
|
|||
// See https://github.com/golang/protobuf/issues/424
|
|||
err := u.Unmarshal(p.buf[p.index:]) |
|||
p.index = len(p.buf) |
|||
return err |
|||
} |
|||
|
|||
// Slow workaround for messages that aren't Unmarshalers.
|
|||
// This includes some hand-coded .pb.go files and
|
|||
// bootstrap protos.
|
|||
// TODO: fix all of those and then add Unmarshal to
|
|||
// the Message interface. Then:
|
|||
// The cast above and code below can be deleted.
|
|||
// The old unmarshaler can be deleted.
|
|||
// Clients can call Unmarshal directly (can already do that, actually).
|
|||
var info InternalMessageInfo |
|||
err := info.Unmarshal(pb, p.buf[p.index:]) |
|||
p.index = len(p.buf) |
|||
return err |
|||
} |
@ -0,0 +1,63 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2018 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 |
|||
|
|||
import "errors" |
|||
|
|||
// Deprecated: do not use.
|
|||
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } |
|||
|
|||
// Deprecated: do not use.
|
|||
func GetStats() Stats { return Stats{} } |
|||
|
|||
// Deprecated: do not use.
|
|||
func MarshalMessageSet(interface{}) ([]byte, error) { |
|||
return nil, errors.New("proto: not implemented") |
|||
} |
|||
|
|||
// Deprecated: do not use.
|
|||
func UnmarshalMessageSet([]byte, interface{}) error { |
|||
return errors.New("proto: not implemented") |
|||
} |
|||
|
|||
// Deprecated: do not use.
|
|||
func MarshalMessageSetJSON(interface{}) ([]byte, error) { |
|||
return nil, errors.New("proto: not implemented") |
|||
} |
|||
|
|||
// Deprecated: do not use.
|
|||
func UnmarshalMessageSetJSON([]byte, interface{}) error { |
|||
return errors.New("proto: not implemented") |
|||
} |
|||
|
|||
// Deprecated: do not use.
|
|||
func RegisterMessageSetType(Message, int32, string) {} |
@ -0,0 +1,350 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2017 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 |
|||
|
|||
import ( |
|||
"fmt" |
|||
"reflect" |
|||
"strings" |
|||
"sync" |
|||
"sync/atomic" |
|||
) |
|||
|
|||
type generatedDiscarder interface { |
|||
XXX_DiscardUnknown() |
|||
} |
|||
|
|||
// DiscardUnknown recursively discards all unknown fields from this message
|
|||
// and all embedded messages.
|
|||
//
|
|||
// When unmarshaling a message with unrecognized fields, the tags and values
|
|||
// of such fields are preserved in the Message. This allows a later call to
|
|||
// marshal to be able to produce a message that continues to have those
|
|||
// unrecognized fields. To avoid this, DiscardUnknown is used to
|
|||
// explicitly clear the unknown fields after unmarshaling.
|
|||
//
|
|||
// For proto2 messages, the unknown fields of message extensions are only
|
|||
// discarded from messages that have been accessed via GetExtension.
|
|||
func DiscardUnknown(m Message) { |
|||
if m, ok := m.(generatedDiscarder); ok { |
|||
m.XXX_DiscardUnknown() |
|||
return |
|||
} |
|||
// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
|
|||
// but the master branch has no implementation for InternalMessageInfo,
|
|||
// so it would be more work to replicate that approach.
|
|||
discardLegacy(m) |
|||
} |
|||
|
|||
// DiscardUnknown recursively discards all unknown fields.
|
|||
func (a *InternalMessageInfo) DiscardUnknown(m Message) { |
|||
di := atomicLoadDiscardInfo(&a.discard) |
|||
if di == nil { |
|||
di = getDiscardInfo(reflect.TypeOf(m).Elem()) |
|||
atomicStoreDiscardInfo(&a.discard, di) |
|||
} |
|||
di.discard(toPointer(&m)) |
|||
} |
|||
|
|||
type discardInfo struct { |
|||
typ reflect.Type |
|||
|
|||
initialized int32 // 0: only typ is valid, 1: everything is valid
|
|||
lock sync.Mutex |
|||
|
|||
fields []discardFieldInfo |
|||
unrecognized field |
|||
} |
|||
|
|||
type discardFieldInfo struct { |
|||
field field // Offset of field, guaranteed to be valid
|
|||
discard func(src pointer) |
|||
} |
|||
|
|||
var ( |
|||
discardInfoMap = map[reflect.Type]*discardInfo{} |
|||
discardInfoLock sync.Mutex |
|||
) |
|||
|
|||
func getDiscardInfo(t reflect.Type) *discardInfo { |
|||
discardInfoLock.Lock() |
|||
defer discardInfoLock.Unlock() |
|||
di := discardInfoMap[t] |
|||
if di == nil { |
|||
di = &discardInfo{typ: t} |
|||
discardInfoMap[t] = di |
|||
} |
|||
return di |
|||
} |
|||
|
|||
func (di *discardInfo) discard(src pointer) { |
|||
if src.isNil() { |
|||
return // Nothing to do.
|
|||
} |
|||
|
|||
if atomic.LoadInt32(&di.initialized) == 0 { |
|||
di.computeDiscardInfo() |
|||
} |
|||
|
|||
for _, fi := range di.fields { |
|||
sfp := src.offset(fi.field) |
|||
fi.discard(sfp) |
|||
} |
|||
|
|||
// For proto2 messages, only discard unknown fields in message extensions
|
|||
// that have been accessed via GetExtension.
|
|||
if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { |
|||
// Ignore lock since DiscardUnknown is not concurrency safe.
|
|||
emm, _ := em.extensionsRead() |
|||
for _, mx := range emm { |
|||
if m, ok := mx.value.(Message); ok { |
|||
DiscardUnknown(m) |
|||
} |
|||
} |
|||
} |
|||
|
|||
if di.unrecognized.IsValid() { |
|||
*src.offset(di.unrecognized).toBytes() = nil |
|||
} |
|||
} |
|||
|
|||
func (di *discardInfo) computeDiscardInfo() { |
|||
di.lock.Lock() |
|||
defer di.lock.Unlock() |
|||
if di.initialized != 0 { |
|||
return |
|||
} |
|||
t := di.typ |
|||
n := t.NumField() |
|||
|
|||
for i := 0; i < n; i++ { |
|||
f := t.Field(i) |
|||
if strings.HasPrefix(f.Name, "XXX_") { |
|||
continue |
|||
} |
|||
|
|||
dfi := discardFieldInfo{field: toField(&f)} |
|||
tf := f.Type |
|||
|
|||
// Unwrap tf to get its most basic type.
|
|||
var isPointer, isSlice bool |
|||
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { |
|||
isSlice = true |
|||
tf = tf.Elem() |
|||
} |
|||
if tf.Kind() == reflect.Ptr { |
|||
isPointer = true |
|||
tf = tf.Elem() |
|||
} |
|||
if isPointer && isSlice && tf.Kind() != reflect.Struct { |
|||
panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) |
|||
} |
|||
|
|||
switch tf.Kind() { |
|||
case reflect.Struct: |
|||
switch { |
|||
case !isPointer: |
|||
panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) |
|||
case isSlice: // E.g., []*pb.T
|
|||
di := getDiscardInfo(tf) |
|||
dfi.discard = func(src pointer) { |
|||
sps := src.getPointerSlice() |
|||
for _, sp := range sps { |
|||
if !sp.isNil() { |
|||
di.discard(sp) |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., *pb.T
|
|||
di := getDiscardInfo(tf) |
|||
dfi.discard = func(src pointer) { |
|||
sp := src.getPointer() |
|||
if !sp.isNil() { |
|||
di.discard(sp) |
|||
} |
|||
} |
|||
} |
|||
case reflect.Map: |
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) |
|||
default: // E.g., map[K]V
|
|||
if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
|
|||
dfi.discard = func(src pointer) { |
|||
sm := src.asPointerTo(tf).Elem() |
|||
if sm.Len() == 0 { |
|||
return |
|||
} |
|||
for _, key := range sm.MapKeys() { |
|||
val := sm.MapIndex(key) |
|||
DiscardUnknown(val.Interface().(Message)) |
|||
} |
|||
} |
|||
} else { |
|||
dfi.discard = func(pointer) {} // Noop
|
|||
} |
|||
} |
|||
case reflect.Interface: |
|||
// Must be oneof field.
|
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) |
|||
default: // E.g., interface{}
|
|||
// TODO: Make this faster?
|
|||
dfi.discard = func(src pointer) { |
|||
su := src.asPointerTo(tf).Elem() |
|||
if !su.IsNil() { |
|||
sv := su.Elem().Elem().Field(0) |
|||
if sv.Kind() == reflect.Ptr && sv.IsNil() { |
|||
return |
|||
} |
|||
switch sv.Type().Kind() { |
|||
case reflect.Ptr: // Proto struct (e.g., *T)
|
|||
DiscardUnknown(sv.Interface().(Message)) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
default: |
|||
continue |
|||
} |
|||
di.fields = append(di.fields, dfi) |
|||
} |
|||
|
|||
di.unrecognized = invalidField |
|||
if f, ok := t.FieldByName("XXX_unrecognized"); ok { |
|||
if f.Type != reflect.TypeOf([]byte{}) { |
|||
panic("expected XXX_unrecognized to be of type []byte") |
|||
} |
|||
di.unrecognized = toField(&f) |
|||
} |
|||
|
|||
atomic.StoreInt32(&di.initialized, 1) |
|||
} |
|||
|
|||
func discardLegacy(m Message) { |
|||
v := reflect.ValueOf(m) |
|||
if v.Kind() != reflect.Ptr || v.IsNil() { |
|||
return |
|||
} |
|||
v = v.Elem() |
|||
if v.Kind() != reflect.Struct { |
|||
return |
|||
} |
|||
t := v.Type() |
|||
|
|||
for i := 0; i < v.NumField(); i++ { |
|||
f := t.Field(i) |
|||
if strings.HasPrefix(f.Name, "XXX_") { |
|||
continue |
|||
} |
|||
vf := v.Field(i) |
|||
tf := f.Type |
|||
|
|||
// Unwrap tf to get its most basic type.
|
|||
var isPointer, isSlice bool |
|||
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { |
|||
isSlice = true |
|||
tf = tf.Elem() |
|||
} |
|||
if tf.Kind() == reflect.Ptr { |
|||
isPointer = true |
|||
tf = tf.Elem() |
|||
} |
|||
if isPointer && isSlice && tf.Kind() != reflect.Struct { |
|||
panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) |
|||
} |
|||
|
|||
switch tf.Kind() { |
|||
case reflect.Struct: |
|||
switch { |
|||
case !isPointer: |
|||
panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) |
|||
case isSlice: // E.g., []*pb.T
|
|||
for j := 0; j < vf.Len(); j++ { |
|||
discardLegacy(vf.Index(j).Interface().(Message)) |
|||
} |
|||
default: // E.g., *pb.T
|
|||
discardLegacy(vf.Interface().(Message)) |
|||
} |
|||
case reflect.Map: |
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) |
|||
default: // E.g., map[K]V
|
|||
tv := vf.Type().Elem() |
|||
if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T)
|
|||
for _, key := range vf.MapKeys() { |
|||
val := vf.MapIndex(key) |
|||
discardLegacy(val.Interface().(Message)) |
|||
} |
|||
} |
|||
} |
|||
case reflect.Interface: |
|||
// Must be oneof field.
|
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) |
|||
default: // E.g., test_proto.isCommunique_Union interface
|
|||
if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { |
|||
vf = vf.Elem() // E.g., *test_proto.Communique_Msg
|
|||
if !vf.IsNil() { |
|||
vf = vf.Elem() // E.g., test_proto.Communique_Msg
|
|||
vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value
|
|||
if vf.Kind() == reflect.Ptr { |
|||
discardLegacy(vf.Interface().(Message)) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { |
|||
if vf.Type() != reflect.TypeOf([]byte{}) { |
|||
panic("expected XXX_unrecognized to be of type []byte") |
|||
} |
|||
vf.Set(reflect.ValueOf([]byte(nil))) |
|||
} |
|||
|
|||
// For proto2 messages, only discard unknown fields in message extensions
|
|||
// that have been accessed via GetExtension.
|
|||
if em, err := extendable(m); err == nil { |
|||
// Ignore lock since discardLegacy is not concurrency safe.
|
|||
emm, _ := em.extensionsRead() |
|||
for _, mx := range emm { |
|||
if m, ok := mx.value.(Message); ok { |
|||
discardLegacy(m) |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,203 @@ |
|||
// 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" |
|||
"reflect" |
|||
) |
|||
|
|||
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") |
|||
|
|||
// errOneofHasNil is the error returned if Marshal is called with
|
|||
// a struct with a oneof field containing a nil element.
|
|||
errOneofHasNil = errors.New("proto: oneof field has nil value") |
|||
|
|||
// ErrNil is the error returned if Marshal is called with nil.
|
|||
ErrNil = errors.New("proto: Marshal called with nil") |
|||
|
|||
// ErrTooLarge is the error returned if Marshal is called with a
|
|||
// message that encodes to >2GB.
|
|||
ErrTooLarge = errors.New("proto: message encodes to over 2 GB") |
|||
) |
|||
|
|||
// 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 { |
|||
switch { |
|||
case x < 1<<7: |
|||
return 1 |
|||
case x < 1<<14: |
|||
return 2 |
|||
case x < 1<<21: |
|||
return 3 |
|||
case x < 1<<28: |
|||
return 4 |
|||
case x < 1<<35: |
|||
return 5 |
|||
case x < 1<<42: |
|||
return 6 |
|||
case x < 1<<49: |
|||
return 7 |
|||
case x < 1<<56: |
|||
return 8 |
|||
case x < 1<<63: |
|||
return 9 |
|||
} |
|||
return 10 |
|||
} |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
// 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)))) |
|||
} |
|||
|
|||
// 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)))) |
|||
} |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
// Marshaler is the interface representing objects that can marshal themselves.
|
|||
type Marshaler interface { |
|||
Marshal() ([]byte, error) |
|||
} |
|||
|
|||
// EncodeMessage writes the protocol buffer to the Buffer,
|
|||
// prefixed by a varint-encoded length.
|
|||
func (p *Buffer) EncodeMessage(pb Message) error { |
|||
siz := Size(pb) |
|||
p.EncodeVarint(uint64(siz)) |
|||
return p.Marshal(pb) |
|||
} |
|||
|
|||
// 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 |
|||
} |
@ -0,0 +1,301 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2011 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.
|
|||
|
|||
// Protocol buffer comparison.
|
|||
|
|||
package proto |
|||
|
|||
import ( |
|||
"bytes" |
|||
"log" |
|||
"reflect" |
|||
"strings" |
|||
) |
|||
|
|||
/* |
|||
Equal returns true iff protocol buffers a and b are equal. |
|||
The arguments must both be pointers to protocol buffer structs. |
|||
|
|||
Equality is defined in this way: |
|||
- Two messages are equal iff they are the same type, |
|||
corresponding fields are equal, unknown field sets |
|||
are equal, and extensions sets are equal. |
|||
- Two set scalar fields are equal iff their values are equal. |
|||
If the fields are of a floating-point type, remember that |
|||
NaN != x for all x, including NaN. If the message is defined |
|||
in a proto3 .proto file, fields are not "set"; specifically, |
|||
zero length proto3 "bytes" fields are equal (nil == {}). |
|||
- Two repeated fields are equal iff their lengths are the same, |
|||
and their corresponding elements are equal. Note a "bytes" field, |
|||
although represented by []byte, is not a repeated field and the |
|||
rule for the scalar fields described above applies. |
|||
- Two unset fields are equal. |
|||
- Two unknown field sets are equal if their current |
|||
encoded state is equal. |
|||
- Two extension sets are equal iff they have corresponding |
|||
elements that are pairwise equal. |
|||
- Two map fields are equal iff their lengths are the same, |
|||
and they contain the same set of elements. Zero-length map |
|||
fields are equal. |
|||
- Every other combination of things are not equal. |
|||
|
|||
The return value is undefined if a and b are not protocol buffers. |
|||
*/ |
|||
func Equal(a, b Message) bool { |
|||
if a == nil || b == nil { |
|||
return a == b |
|||
} |
|||
v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) |
|||
if v1.Type() != v2.Type() { |
|||
return false |
|||
} |
|||
if v1.Kind() == reflect.Ptr { |
|||
if v1.IsNil() { |
|||
return v2.IsNil() |
|||
} |
|||
if v2.IsNil() { |
|||
return false |
|||
} |
|||
v1, v2 = v1.Elem(), v2.Elem() |
|||
} |
|||
if v1.Kind() != reflect.Struct { |
|||
return false |
|||
} |
|||
return equalStruct(v1, v2) |
|||
} |
|||
|
|||
// v1 and v2 are known to have the same type.
|
|||
func equalStruct(v1, v2 reflect.Value) bool { |
|||
sprop := GetProperties(v1.Type()) |
|||
for i := 0; i < v1.NumField(); i++ { |
|||
f := v1.Type().Field(i) |
|||
if strings.HasPrefix(f.Name, "XXX_") { |
|||
continue |
|||
} |
|||
f1, f2 := v1.Field(i), v2.Field(i) |
|||
if f.Type.Kind() == reflect.Ptr { |
|||
if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { |
|||
// both unset
|
|||
continue |
|||
} else if n1 != n2 { |
|||
// set/unset mismatch
|
|||
return false |
|||
} |
|||
f1, f2 = f1.Elem(), f2.Elem() |
|||
} |
|||
if !equalAny(f1, f2, sprop.Prop[i]) { |
|||
return false |
|||
} |
|||
} |
|||
|
|||
if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { |
|||
em2 := v2.FieldByName("XXX_InternalExtensions") |
|||
if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { |
|||
return false |
|||
} |
|||
} |
|||
|
|||
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { |
|||
em2 := v2.FieldByName("XXX_extensions") |
|||
if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { |
|||
return false |
|||
} |
|||
} |
|||
|
|||
uf := v1.FieldByName("XXX_unrecognized") |
|||
if !uf.IsValid() { |
|||
return true |
|||
} |
|||
|
|||
u1 := uf.Bytes() |
|||
u2 := v2.FieldByName("XXX_unrecognized").Bytes() |
|||
return bytes.Equal(u1, u2) |
|||
} |
|||
|
|||
// v1 and v2 are known to have the same type.
|
|||
// prop may be nil.
|
|||
func equalAny(v1, v2 reflect.Value, prop *Properties) bool { |
|||
if v1.Type() == protoMessageType { |
|||
m1, _ := v1.Interface().(Message) |
|||
m2, _ := v2.Interface().(Message) |
|||
return Equal(m1, m2) |
|||
} |
|||
switch v1.Kind() { |
|||
case reflect.Bool: |
|||
return v1.Bool() == v2.Bool() |
|||
case reflect.Float32, reflect.Float64: |
|||
return v1.Float() == v2.Float() |
|||
case reflect.Int32, reflect.Int64: |
|||
return v1.Int() == v2.Int() |
|||
case reflect.Interface: |
|||
// Probably a oneof field; compare the inner values.
|
|||
n1, n2 := v1.IsNil(), v2.IsNil() |
|||
if n1 || n2 { |
|||
return n1 == n2 |
|||
} |
|||
e1, e2 := v1.Elem(), v2.Elem() |
|||
if e1.Type() != e2.Type() { |
|||
return false |
|||
} |
|||
return equalAny(e1, e2, nil) |
|||
case reflect.Map: |
|||
if v1.Len() != v2.Len() { |
|||
return false |
|||
} |
|||
for _, key := range v1.MapKeys() { |
|||
val2 := v2.MapIndex(key) |
|||
if !val2.IsValid() { |
|||
// This key was not found in the second map.
|
|||
return false |
|||
} |
|||
if !equalAny(v1.MapIndex(key), val2, nil) { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
case reflect.Ptr: |
|||
// Maps may have nil values in them, so check for nil.
|
|||
if v1.IsNil() && v2.IsNil() { |
|||
return true |
|||
} |
|||
if v1.IsNil() != v2.IsNil() { |
|||
return false |
|||
} |
|||
return equalAny(v1.Elem(), v2.Elem(), prop) |
|||
case reflect.Slice: |
|||
if v1.Type().Elem().Kind() == reflect.Uint8 { |
|||
// short circuit: []byte
|
|||
|
|||
// Edge case: if this is in a proto3 message, a zero length
|
|||
// bytes field is considered the zero value.
|
|||
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { |
|||
return true |
|||
} |
|||
if v1.IsNil() != v2.IsNil() { |
|||
return false |
|||
} |
|||
return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) |
|||
} |
|||
|
|||
if v1.Len() != v2.Len() { |
|||
return false |
|||
} |
|||
for i := 0; i < v1.Len(); i++ { |
|||
if !equalAny(v1.Index(i), v2.Index(i), prop) { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
case reflect.String: |
|||
return v1.Interface().(string) == v2.Interface().(string) |
|||
case reflect.Struct: |
|||
return equalStruct(v1, v2) |
|||
case reflect.Uint32, reflect.Uint64: |
|||
return v1.Uint() == v2.Uint() |
|||
} |
|||
|
|||
// unknown type, so not a protocol buffer
|
|||
log.Printf("proto: don't know how to compare %v", v1) |
|||
return false |
|||
} |
|||
|
|||
// base is the struct type that the extensions are based on.
|
|||
// x1 and x2 are InternalExtensions.
|
|||
func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { |
|||
em1, _ := x1.extensionsRead() |
|||
em2, _ := x2.extensionsRead() |
|||
return equalExtMap(base, em1, em2) |
|||
} |
|||
|
|||
func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { |
|||
if len(em1) != len(em2) { |
|||
return false |
|||
} |
|||
|
|||
for extNum, e1 := range em1 { |
|||
e2, ok := em2[extNum] |
|||
if !ok { |
|||
return false |
|||
} |
|||
|
|||
m1 := extensionAsLegacyType(e1.value) |
|||
m2 := extensionAsLegacyType(e2.value) |
|||
|
|||
if m1 == nil && m2 == nil { |
|||
// Both have only encoded form.
|
|||
if bytes.Equal(e1.enc, e2.enc) { |
|||
continue |
|||
} |
|||
// The bytes are different, but the extensions might still be
|
|||
// equal. We need to decode them to compare.
|
|||
} |
|||
|
|||
if m1 != nil && m2 != nil { |
|||
// Both are unencoded.
|
|||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { |
|||
return false |
|||
} |
|||
continue |
|||
} |
|||
|
|||
// At least one is encoded. To do a semantically correct comparison
|
|||
// we need to unmarshal them first.
|
|||
var desc *ExtensionDesc |
|||
if m := extensionMaps[base]; m != nil { |
|||
desc = m[extNum] |
|||
} |
|||
if desc == nil { |
|||
// If both have only encoded form and the bytes are the same,
|
|||
// it is handled above. We get here when the bytes are different.
|
|||
// We don't know how to decode it, so just compare them as byte
|
|||
// slices.
|
|||
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) |
|||
return false |
|||
} |
|||
var err error |
|||
if m1 == nil { |
|||
m1, err = decodeExtension(e1.enc, desc) |
|||
} |
|||
if m2 == nil && err == nil { |
|||
m2, err = decodeExtension(e2.enc, desc) |
|||
} |
|||
if err != nil { |
|||
// The encoded form is invalid.
|
|||
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) |
|||
return false |
|||
} |
|||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { |
|||
return false |
|||
} |
|||
} |
|||
|
|||
return true |
|||
} |
@ -0,0 +1,607 @@ |
|||
// 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 |
|||
|
|||
/* |
|||
* Types and routines for supporting protocol buffer extensions. |
|||
*/ |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"io" |
|||
"reflect" |
|||
"strconv" |
|||
"sync" |
|||
) |
|||
|
|||
// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
|
|||
var ErrMissingExtension = errors.New("proto: missing extension") |
|||
|
|||
// ExtensionRange represents a range of message extensions for a protocol buffer.
|
|||
// Used in code generated by the protocol compiler.
|
|||
type ExtensionRange struct { |
|||
Start, End int32 // both inclusive
|
|||
} |
|||
|
|||
// extendableProto is an interface implemented by any protocol buffer generated by the current
|
|||
// proto compiler that may be extended.
|
|||
type extendableProto interface { |
|||
Message |
|||
ExtensionRangeArray() []ExtensionRange |
|||
extensionsWrite() map[int32]Extension |
|||
extensionsRead() (map[int32]Extension, sync.Locker) |
|||
} |
|||
|
|||
// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous
|
|||
// version of the proto compiler that may be extended.
|
|||
type extendableProtoV1 interface { |
|||
Message |
|||
ExtensionRangeArray() []ExtensionRange |
|||
ExtensionMap() map[int32]Extension |
|||
} |
|||
|
|||
// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto.
|
|||
type extensionAdapter struct { |
|||
extendableProtoV1 |
|||
} |
|||
|
|||
func (e extensionAdapter) extensionsWrite() map[int32]Extension { |
|||
return e.ExtensionMap() |
|||
} |
|||
|
|||
func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { |
|||
return e.ExtensionMap(), notLocker{} |
|||
} |
|||
|
|||
// notLocker is a sync.Locker whose Lock and Unlock methods are nops.
|
|||
type notLocker struct{} |
|||
|
|||
func (n notLocker) Lock() {} |
|||
func (n notLocker) Unlock() {} |
|||
|
|||
// extendable returns the extendableProto interface for the given generated proto message.
|
|||
// If the proto message has the old extension format, it returns a wrapper that implements
|
|||
// the extendableProto interface.
|
|||
func extendable(p interface{}) (extendableProto, error) { |
|||
switch p := p.(type) { |
|||
case extendableProto: |
|||
if isNilPtr(p) { |
|||
return nil, fmt.Errorf("proto: nil %T is not extendable", p) |
|||
} |
|||
return p, nil |
|||
case extendableProtoV1: |
|||
if isNilPtr(p) { |
|||
return nil, fmt.Errorf("proto: nil %T is not extendable", p) |
|||
} |
|||
return extensionAdapter{p}, nil |
|||
} |
|||
// Don't allocate a specific error containing %T:
|
|||
// this is the hot path for Clone and MarshalText.
|
|||
return nil, errNotExtendable |
|||
} |
|||
|
|||
var errNotExtendable = errors.New("proto: not an extendable proto.Message") |
|||
|
|||
func isNilPtr(x interface{}) bool { |
|||
v := reflect.ValueOf(x) |
|||
return v.Kind() == reflect.Ptr && v.IsNil() |
|||
} |
|||
|
|||
// XXX_InternalExtensions is an internal representation of proto extensions.
|
|||
//
|
|||
// Each generated message struct type embeds an anonymous XXX_InternalExtensions field,
|
|||
// thus gaining the unexported 'extensions' method, which can be called only from the proto package.
|
|||
//
|
|||
// The methods of XXX_InternalExtensions are not concurrency safe in general,
|
|||
// but calls to logically read-only methods such as has and get may be executed concurrently.
|
|||
type XXX_InternalExtensions struct { |
|||
// The struct must be indirect so that if a user inadvertently copies a
|
|||
// generated message and its embedded XXX_InternalExtensions, they
|
|||
// avoid the mayhem of a copied mutex.
|
|||
//
|
|||
// The mutex serializes all logically read-only operations to p.extensionMap.
|
|||
// It is up to the client to ensure that write operations to p.extensionMap are
|
|||
// mutually exclusive with other accesses.
|
|||
p *struct { |
|||
mu sync.Mutex |
|||
extensionMap map[int32]Extension |
|||
} |
|||
} |
|||
|
|||
// extensionsWrite returns the extension map, creating it on first use.
|
|||
func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { |
|||
if e.p == nil { |
|||
e.p = new(struct { |
|||
mu sync.Mutex |
|||
extensionMap map[int32]Extension |
|||
}) |
|||
e.p.extensionMap = make(map[int32]Extension) |
|||
} |
|||
return e.p.extensionMap |
|||
} |
|||
|
|||
// extensionsRead returns the extensions map for read-only use. It may be nil.
|
|||
// The caller must hold the returned mutex's lock when accessing Elements within the map.
|
|||
func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { |
|||
if e.p == nil { |
|||
return nil, nil |
|||
} |
|||
return e.p.extensionMap, &e.p.mu |
|||
} |
|||
|
|||
// ExtensionDesc represents an extension specification.
|
|||
// Used in generated code from the protocol compiler.
|
|||
type ExtensionDesc struct { |
|||
ExtendedType Message // nil pointer to the type that is being extended
|
|||
ExtensionType interface{} // nil pointer to the extension type
|
|||
Field int32 // field number
|
|||
Name string // fully-qualified name of extension, for text formatting
|
|||
Tag string // protobuf tag style
|
|||
Filename string // name of the file in which the extension is defined
|
|||
} |
|||
|
|||
func (ed *ExtensionDesc) repeated() bool { |
|||
t := reflect.TypeOf(ed.ExtensionType) |
|||
return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 |
|||
} |
|||
|
|||
// Extension represents an extension in a message.
|
|||
type Extension struct { |
|||
// When an extension is stored in a message using SetExtension
|
|||
// only desc and value are set. When the message is marshaled
|
|||
// enc will be set to the encoded form of the message.
|
|||
//
|
|||
// When a message is unmarshaled and contains extensions, each
|
|||
// extension will have only enc set. When such an extension is
|
|||
// accessed using GetExtension (or GetExtensions) desc and value
|
|||
// will be set.
|
|||
desc *ExtensionDesc |
|||
|
|||
// value is a concrete value for the extension field. Let the type of
|
|||
// desc.ExtensionType be the "API type" and the type of Extension.value
|
|||
// be the "storage type". The API type and storage type are the same except:
|
|||
// * For scalars (except []byte), the API type uses *T,
|
|||
// while the storage type uses T.
|
|||
// * For repeated fields, the API type uses []T, while the storage type
|
|||
// uses *[]T.
|
|||
//
|
|||
// The reason for the divergence is so that the storage type more naturally
|
|||
// matches what is expected of when retrieving the values through the
|
|||
// protobuf reflection APIs.
|
|||
//
|
|||
// The value may only be populated if desc is also populated.
|
|||
value interface{} |
|||
|
|||
// enc is the raw bytes for the extension field.
|
|||
enc []byte |
|||
} |
|||
|
|||
// SetRawExtension is for testing only.
|
|||
func SetRawExtension(base Message, id int32, b []byte) { |
|||
epb, err := extendable(base) |
|||
if err != nil { |
|||
return |
|||
} |
|||
extmap := epb.extensionsWrite() |
|||
extmap[id] = Extension{enc: b} |
|||
} |
|||
|
|||
// isExtensionField returns true iff the given field number is in an extension range.
|
|||
func isExtensionField(pb extendableProto, field int32) bool { |
|||
for _, er := range pb.ExtensionRangeArray() { |
|||
if er.Start <= field && field <= er.End { |
|||
return true |
|||
} |
|||
} |
|||
return false |
|||
} |
|||
|
|||
// checkExtensionTypes checks that the given extension is valid for pb.
|
|||
func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { |
|||
var pbi interface{} = pb |
|||
// Check the extended type.
|
|||
if ea, ok := pbi.(extensionAdapter); ok { |
|||
pbi = ea.extendableProtoV1 |
|||
} |
|||
if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { |
|||
return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) |
|||
} |
|||
// Check the range.
|
|||
if !isExtensionField(pb, extension.Field) { |
|||
return errors.New("proto: bad extension number; not in declared ranges") |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// extPropKey is sufficient to uniquely identify an extension.
|
|||
type extPropKey struct { |
|||
base reflect.Type |
|||
field int32 |
|||
} |
|||
|
|||
var extProp = struct { |
|||
sync.RWMutex |
|||
m map[extPropKey]*Properties |
|||
}{ |
|||
m: make(map[extPropKey]*Properties), |
|||
} |
|||
|
|||
func extensionProperties(ed *ExtensionDesc) *Properties { |
|||
key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} |
|||
|
|||
extProp.RLock() |
|||
if prop, ok := extProp.m[key]; ok { |
|||
extProp.RUnlock() |
|||
return prop |
|||
} |
|||
extProp.RUnlock() |
|||
|
|||
extProp.Lock() |
|||
defer extProp.Unlock() |
|||
// Check again.
|
|||
if prop, ok := extProp.m[key]; ok { |
|||
return prop |
|||
} |
|||
|
|||
prop := new(Properties) |
|||
prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) |
|||
extProp.m[key] = prop |
|||
return prop |
|||
} |
|||
|
|||
// HasExtension returns whether the given extension is present in pb.
|
|||
func HasExtension(pb Message, extension *ExtensionDesc) bool { |
|||
// TODO: Check types, field numbers, etc.?
|
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return false |
|||
} |
|||
extmap, mu := epb.extensionsRead() |
|||
if extmap == nil { |
|||
return false |
|||
} |
|||
mu.Lock() |
|||
_, ok := extmap[extension.Field] |
|||
mu.Unlock() |
|||
return ok |
|||
} |
|||
|
|||
// ClearExtension removes the given extension from pb.
|
|||
func ClearExtension(pb Message, extension *ExtensionDesc) { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return |
|||
} |
|||
// TODO: Check types, field numbers, etc.?
|
|||
extmap := epb.extensionsWrite() |
|||
delete(extmap, extension.Field) |
|||
} |
|||
|
|||
// GetExtension retrieves a proto2 extended field from pb.
|
|||
//
|
|||
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
|
|||
// then GetExtension parses the encoded field and returns a Go value of the specified type.
|
|||
// If the field is not present, then the default value is returned (if one is specified),
|
|||
// otherwise ErrMissingExtension is reported.
|
|||
//
|
|||
// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil),
|
|||
// then GetExtension returns the raw encoded bytes of the field extension.
|
|||
func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if extension.ExtendedType != nil { |
|||
// can only check type if this is a complete descriptor
|
|||
if err := checkExtensionTypes(epb, extension); err != nil { |
|||
return nil, err |
|||
} |
|||
} |
|||
|
|||
emap, mu := epb.extensionsRead() |
|||
if emap == nil { |
|||
return defaultExtensionValue(extension) |
|||
} |
|||
mu.Lock() |
|||
defer mu.Unlock() |
|||
e, ok := emap[extension.Field] |
|||
if !ok { |
|||
// defaultExtensionValue returns the default value or
|
|||
// ErrMissingExtension if there is no default.
|
|||
return defaultExtensionValue(extension) |
|||
} |
|||
|
|||
if e.value != nil { |
|||
// Already decoded. Check the descriptor, though.
|
|||
if e.desc != extension { |
|||
// This shouldn't happen. If it does, it means that
|
|||
// GetExtension was called twice with two different
|
|||
// descriptors with the same field number.
|
|||
return nil, errors.New("proto: descriptor conflict") |
|||
} |
|||
return extensionAsLegacyType(e.value), nil |
|||
} |
|||
|
|||
if extension.ExtensionType == nil { |
|||
// incomplete descriptor
|
|||
return e.enc, nil |
|||
} |
|||
|
|||
v, err := decodeExtension(e.enc, extension) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// Remember the decoded version and drop the encoded version.
|
|||
// That way it is safe to mutate what we return.
|
|||
e.value = extensionAsStorageType(v) |
|||
e.desc = extension |
|||
e.enc = nil |
|||
emap[extension.Field] = e |
|||
return extensionAsLegacyType(e.value), nil |
|||
} |
|||
|
|||
// defaultExtensionValue returns the default value for extension.
|
|||
// If no default for an extension is defined ErrMissingExtension is returned.
|
|||
func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { |
|||
if extension.ExtensionType == nil { |
|||
// incomplete descriptor, so no default
|
|||
return nil, ErrMissingExtension |
|||
} |
|||
|
|||
t := reflect.TypeOf(extension.ExtensionType) |
|||
props := extensionProperties(extension) |
|||
|
|||
sf, _, err := fieldDefault(t, props) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if sf == nil || sf.value == nil { |
|||
// There is no default value.
|
|||
return nil, ErrMissingExtension |
|||
} |
|||
|
|||
if t.Kind() != reflect.Ptr { |
|||
// We do not need to return a Ptr, we can directly return sf.value.
|
|||
return sf.value, nil |
|||
} |
|||
|
|||
// We need to return an interface{} that is a pointer to sf.value.
|
|||
value := reflect.New(t).Elem() |
|||
value.Set(reflect.New(value.Type().Elem())) |
|||
if sf.kind == reflect.Int32 { |
|||
// We may have an int32 or an enum, but the underlying data is int32.
|
|||
// Since we can't set an int32 into a non int32 reflect.value directly
|
|||
// set it as a int32.
|
|||
value.Elem().SetInt(int64(sf.value.(int32))) |
|||
} else { |
|||
value.Elem().Set(reflect.ValueOf(sf.value)) |
|||
} |
|||
return value.Interface(), nil |
|||
} |
|||
|
|||
// decodeExtension decodes an extension encoded in b.
|
|||
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { |
|||
t := reflect.TypeOf(extension.ExtensionType) |
|||
unmarshal := typeUnmarshaler(t, extension.Tag) |
|||
|
|||
// t is a pointer to a struct, pointer to basic type or a slice.
|
|||
// Allocate space to store the pointer/slice.
|
|||
value := reflect.New(t).Elem() |
|||
|
|||
var err error |
|||
for { |
|||
x, n := decodeVarint(b) |
|||
if n == 0 { |
|||
return nil, io.ErrUnexpectedEOF |
|||
} |
|||
b = b[n:] |
|||
wire := int(x) & 7 |
|||
|
|||
b, err = unmarshal(b, valToPointer(value.Addr()), wire) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
if len(b) == 0 { |
|||
break |
|||
} |
|||
} |
|||
return value.Interface(), nil |
|||
} |
|||
|
|||
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
|
|||
// The returned slice has the same length as es; missing extensions will appear as nil elements.
|
|||
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
extensions = make([]interface{}, len(es)) |
|||
for i, e := range es { |
|||
extensions[i], err = GetExtension(epb, e) |
|||
if err == ErrMissingExtension { |
|||
err = nil |
|||
} |
|||
if err != nil { |
|||
return |
|||
} |
|||
} |
|||
return |
|||
} |
|||
|
|||
// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order.
|
|||
// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
|
|||
// just the Field field, which defines the extension's field number.
|
|||
func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
registeredExtensions := RegisteredExtensions(pb) |
|||
|
|||
emap, mu := epb.extensionsRead() |
|||
if emap == nil { |
|||
return nil, nil |
|||
} |
|||
mu.Lock() |
|||
defer mu.Unlock() |
|||
extensions := make([]*ExtensionDesc, 0, len(emap)) |
|||
for extid, e := range emap { |
|||
desc := e.desc |
|||
if desc == nil { |
|||
desc = registeredExtensions[extid] |
|||
if desc == nil { |
|||
desc = &ExtensionDesc{Field: extid} |
|||
} |
|||
} |
|||
|
|||
extensions = append(extensions, desc) |
|||
} |
|||
return extensions, nil |
|||
} |
|||
|
|||
// SetExtension sets the specified extension of pb to the specified value.
|
|||
func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if err := checkExtensionTypes(epb, extension); err != nil { |
|||
return err |
|||
} |
|||
typ := reflect.TypeOf(extension.ExtensionType) |
|||
if typ != reflect.TypeOf(value) { |
|||
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) |
|||
} |
|||
// nil extension values need to be caught early, because the
|
|||
// encoder can't distinguish an ErrNil due to a nil extension
|
|||
// from an ErrNil due to a missing field. Extensions are
|
|||
// always optional, so the encoder would just swallow the error
|
|||
// and drop all the extensions from the encoded message.
|
|||
if reflect.ValueOf(value).IsNil() { |
|||
return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) |
|||
} |
|||
|
|||
extmap := epb.extensionsWrite() |
|||
extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} |
|||
return nil |
|||
} |
|||
|
|||
// ClearAllExtensions clears all extensions from pb.
|
|||
func ClearAllExtensions(pb Message) { |
|||
epb, err := extendable(pb) |
|||
if err != nil { |
|||
return |
|||
} |
|||
m := epb.extensionsWrite() |
|||
for k := range m { |
|||
delete(m, k) |
|||
} |
|||
} |
|||
|
|||
// A global registry of extensions.
|
|||
// The generated code will register the generated descriptors by calling RegisterExtension.
|
|||
|
|||
var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) |
|||
|
|||
// RegisterExtension is called from the generated code.
|
|||
func RegisterExtension(desc *ExtensionDesc) { |
|||
st := reflect.TypeOf(desc.ExtendedType).Elem() |
|||
m := extensionMaps[st] |
|||
if m == nil { |
|||
m = make(map[int32]*ExtensionDesc) |
|||
extensionMaps[st] = m |
|||
} |
|||
if _, ok := m[desc.Field]; ok { |
|||
panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) |
|||
} |
|||
m[desc.Field] = desc |
|||
} |
|||
|
|||
// RegisteredExtensions returns a map of the registered extensions of a
|
|||
// protocol buffer struct, indexed by the extension number.
|
|||
// The argument pb should be a nil pointer to the struct type.
|
|||
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { |
|||
return extensionMaps[reflect.TypeOf(pb).Elem()] |
|||
} |
|||
|
|||
// extensionAsLegacyType converts an value in the storage type as the API type.
|
|||
// See Extension.value.
|
|||
func extensionAsLegacyType(v interface{}) interface{} { |
|||
switch rv := reflect.ValueOf(v); rv.Kind() { |
|||
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: |
|||
// Represent primitive types as a pointer to the value.
|
|||
rv2 := reflect.New(rv.Type()) |
|||
rv2.Elem().Set(rv) |
|||
v = rv2.Interface() |
|||
case reflect.Ptr: |
|||
// Represent slice types as the value itself.
|
|||
switch rv.Type().Elem().Kind() { |
|||
case reflect.Slice: |
|||
if rv.IsNil() { |
|||
v = reflect.Zero(rv.Type().Elem()).Interface() |
|||
} else { |
|||
v = rv.Elem().Interface() |
|||
} |
|||
} |
|||
} |
|||
return v |
|||
} |
|||
|
|||
// extensionAsStorageType converts an value in the API type as the storage type.
|
|||
// See Extension.value.
|
|||
func extensionAsStorageType(v interface{}) interface{} { |
|||
switch rv := reflect.ValueOf(v); rv.Kind() { |
|||
case reflect.Ptr: |
|||
// Represent slice types as the value itself.
|
|||
switch rv.Type().Elem().Kind() { |
|||
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: |
|||
if rv.IsNil() { |
|||
v = reflect.Zero(rv.Type().Elem()).Interface() |
|||
} else { |
|||
v = rv.Elem().Interface() |
|||
} |
|||
} |
|||
case reflect.Slice: |
|||
// Represent slice types as a pointer to the value.
|
|||
if rv.Type().Elem().Kind() != reflect.Uint8 { |
|||
rv2 := reflect.New(rv.Type()) |
|||
rv2.Elem().Set(rv) |
|||
v = rv2.Interface() |
|||
} |
|||
} |
|||
return v |
|||
} |
@ -0,0 +1,965 @@ |
|||
// 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 converts data structures to and from the wire format of |
|||
protocol buffers. It works in concert with the Go source code generated |
|||
for .proto files by the protocol compiler. |
|||
|
|||
A summary of the properties of the protocol buffer interface |
|||
for a protocol buffer variable v: |
|||
|
|||
- Names are turned from camel_case to CamelCase for export. |
|||
- There are no methods on v to set fields; just treat |
|||
them as structure fields. |
|||
- There are getters that return a field's value if set, |
|||
and return the field's default value if unset. |
|||
The getters work even if the receiver is a nil message. |
|||
- The zero value for a struct is its correct initialization state. |
|||
All desired fields must be set before marshaling. |
|||
- A Reset() method will restore a protobuf struct to its zero state. |
|||
- Non-repeated fields are pointers to the values; nil means unset. |
|||
That is, optional or required field int32 f becomes F *int32. |
|||
- Repeated fields are slices. |
|||
- Helper functions are available to aid the setting of fields. |
|||
msg.Foo = proto.String("hello") // set field
|
|||
- Constants are defined to hold the default values of all fields that |
|||
have them. They have the form Default_StructName_FieldName. |
|||
Because the getter methods handle defaulted values, |
|||
direct use of these constants should be rare. |
|||
- Enums are given type names and maps from names to values. |
|||
Enum values are prefixed by the enclosing message's name, or by the |
|||
enum's type name if it is a top-level enum. Enum types have a String |
|||
method, and a Enum method to assist in message construction. |
|||
- Nested messages, groups and enums have type names prefixed with the name of |
|||
the surrounding message type. |
|||
- Extensions are given descriptor names that start with E_, |
|||
followed by an underscore-delimited list of the nested messages |
|||
that contain it (if any) followed by the CamelCased name of the |
|||
extension field itself. HasExtension, ClearExtension, GetExtension |
|||
and SetExtension are functions for manipulating extensions. |
|||
- Oneof field sets are given a single field in their message, |
|||
with distinguished wrapper types for each possible field value. |
|||
- Marshal and Unmarshal are functions to encode and decode the wire format. |
|||
|
|||
When the .proto file specifies `syntax="proto3"`, there are some differences: |
|||
|
|||
- Non-repeated fields of non-message type are values instead of pointers. |
|||
- Enum types do not get an Enum method. |
|||
|
|||
The simplest way to describe this is to see an example. |
|||
Given file test.proto, containing |
|||
|
|||
package example; |
|||
|
|||
enum FOO { X = 17; } |
|||
|
|||
message Test { |
|||
required string label = 1; |
|||
optional int32 type = 2 [default=77]; |
|||
repeated int64 reps = 3; |
|||
optional group OptionalGroup = 4 { |
|||
required string RequiredField = 5; |
|||
} |
|||
oneof union { |
|||
int32 number = 6; |
|||
string name = 7; |
|||
} |
|||
} |
|||
|
|||
The resulting file, test.pb.go, is: |
|||
|
|||
package example |
|||
|
|||
import proto "github.com/golang/protobuf/proto" |
|||
import math "math" |
|||
|
|||
type FOO int32 |
|||
const ( |
|||
FOO_X FOO = 17 |
|||
) |
|||
var FOO_name = map[int32]string{ |
|||
17: "X", |
|||
} |
|||
var FOO_value = map[string]int32{ |
|||
"X": 17, |
|||
} |
|||
|
|||
func (x FOO) Enum() *FOO { |
|||
p := new(FOO) |
|||
*p = x |
|||
return p |
|||
} |
|||
func (x FOO) String() string { |
|||
return proto.EnumName(FOO_name, int32(x)) |
|||
} |
|||
func (x *FOO) UnmarshalJSON(data []byte) error { |
|||
value, err := proto.UnmarshalJSONEnum(FOO_value, data) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*x = FOO(value) |
|||
return nil |
|||
} |
|||
|
|||
type Test struct { |
|||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` |
|||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` |
|||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` |
|||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` |
|||
// Types that are valid to be assigned to Union:
|
|||
// *Test_Number
|
|||
// *Test_Name
|
|||
Union isTest_Union `protobuf_oneof:"union"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
} |
|||
func (m *Test) Reset() { *m = Test{} } |
|||
func (m *Test) String() string { return proto.CompactTextString(m) } |
|||
func (*Test) ProtoMessage() {} |
|||
|
|||
type isTest_Union interface { |
|||
isTest_Union() |
|||
} |
|||
|
|||
type Test_Number struct { |
|||
Number int32 `protobuf:"varint,6,opt,name=number"` |
|||
} |
|||
type Test_Name struct { |
|||
Name string `protobuf:"bytes,7,opt,name=name"` |
|||
} |
|||
|
|||
func (*Test_Number) isTest_Union() {} |
|||
func (*Test_Name) isTest_Union() {} |
|||
|
|||
func (m *Test) GetUnion() isTest_Union { |
|||
if m != nil { |
|||
return m.Union |
|||
} |
|||
return nil |
|||
} |
|||
const Default_Test_Type int32 = 77 |
|||
|
|||
func (m *Test) GetLabel() string { |
|||
if m != nil && m.Label != nil { |
|||
return *m.Label |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func (m *Test) GetType() int32 { |
|||
if m != nil && m.Type != nil { |
|||
return *m.Type |
|||
} |
|||
return Default_Test_Type |
|||
} |
|||
|
|||
func (m *Test) GetOptionalgroup() *Test_OptionalGroup { |
|||
if m != nil { |
|||
return m.Optionalgroup |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
type Test_OptionalGroup struct { |
|||
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` |
|||
} |
|||
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } |
|||
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } |
|||
|
|||
func (m *Test_OptionalGroup) GetRequiredField() string { |
|||
if m != nil && m.RequiredField != nil { |
|||
return *m.RequiredField |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func (m *Test) GetNumber() int32 { |
|||
if x, ok := m.GetUnion().(*Test_Number); ok { |
|||
return x.Number |
|||
} |
|||
return 0 |
|||
} |
|||
|
|||
func (m *Test) GetName() string { |
|||
if x, ok := m.GetUnion().(*Test_Name); ok { |
|||
return x.Name |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func init() { |
|||
proto.RegisterEnum("example.FOO", FOO_name, FOO_value) |
|||
} |
|||
|
|||
To create and play with a Test object: |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"log" |
|||
|
|||
"github.com/golang/protobuf/proto" |
|||
pb "./example.pb" |
|||
) |
|||
|
|||
func main() { |
|||
test := &pb.Test{ |
|||
Label: proto.String("hello"), |
|||
Type: proto.Int32(17), |
|||
Reps: []int64{1, 2, 3}, |
|||
Optionalgroup: &pb.Test_OptionalGroup{ |
|||
RequiredField: proto.String("good bye"), |
|||
}, |
|||
Union: &pb.Test_Name{"fred"}, |
|||
} |
|||
data, err := proto.Marshal(test) |
|||
if err != nil { |
|||
log.Fatal("marshaling error: ", err) |
|||
} |
|||
newTest := &pb.Test{} |
|||
err = proto.Unmarshal(data, newTest) |
|||
if err != nil { |
|||
log.Fatal("unmarshaling error: ", err) |
|||
} |
|||
// Now test and newTest contain the same data.
|
|||
if test.GetLabel() != newTest.GetLabel() { |
|||
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) |
|||
} |
|||
// Use a type switch to determine which oneof was set.
|
|||
switch u := test.Union.(type) { |
|||
case *pb.Test_Number: // u.Number contains the number.
|
|||
case *pb.Test_Name: // u.Name contains the string.
|
|||
} |
|||
// etc.
|
|||
} |
|||
*/ |
|||
package proto |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"fmt" |
|||
"log" |
|||
"reflect" |
|||
"sort" |
|||
"strconv" |
|||
"sync" |
|||
) |
|||
|
|||
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
|
|||
// Marshal reports this when a required field is not initialized.
|
|||
// Unmarshal reports this when a required field is missing from the wire data.
|
|||
type RequiredNotSetError struct{ field string } |
|||
|
|||
func (e *RequiredNotSetError) Error() string { |
|||
if e.field == "" { |
|||
return fmt.Sprintf("proto: required field not set") |
|||
} |
|||
return fmt.Sprintf("proto: required field %q not set", e.field) |
|||
} |
|||
func (e *RequiredNotSetError) RequiredNotSet() bool { |
|||
return true |
|||
} |
|||
|
|||
type invalidUTF8Error struct{ field string } |
|||
|
|||
func (e *invalidUTF8Error) Error() string { |
|||
if e.field == "" { |
|||
return "proto: invalid UTF-8 detected" |
|||
} |
|||
return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) |
|||
} |
|||
func (e *invalidUTF8Error) InvalidUTF8() bool { |
|||
return true |
|||
} |
|||
|
|||
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
|
|||
// This error should not be exposed to the external API as such errors should
|
|||
// be recreated with the field information.
|
|||
var errInvalidUTF8 = &invalidUTF8Error{} |
|||
|
|||
// isNonFatal reports whether the error is either a RequiredNotSet error
|
|||
// or a InvalidUTF8 error.
|
|||
func isNonFatal(err error) bool { |
|||
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { |
|||
return true |
|||
} |
|||
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
type nonFatal struct{ E error } |
|||
|
|||
// Merge merges err into nf and reports whether it was successful.
|
|||
// Otherwise it returns false for any fatal non-nil errors.
|
|||
func (nf *nonFatal) Merge(err error) (ok bool) { |
|||
if err == nil { |
|||
return true // not an error
|
|||
} |
|||
if !isNonFatal(err) { |
|||
return false // fatal error
|
|||
} |
|||
if nf.E == nil { |
|||
nf.E = err // store first instance of non-fatal error
|
|||
} |
|||
return true |
|||
} |
|||
|
|||
// Message is implemented by generated protocol buffer messages.
|
|||
type Message interface { |
|||
Reset() |
|||
String() string |
|||
ProtoMessage() |
|||
} |
|||
|
|||
// A Buffer is a buffer manager for marshaling and unmarshaling
|
|||
// protocol buffers. It may be reused between invocations to
|
|||
// reduce memory usage. It is not necessary to use a Buffer;
|
|||
// the global functions Marshal and Unmarshal create a
|
|||
// temporary Buffer and are fine for most applications.
|
|||
type Buffer struct { |
|||
buf []byte // encode/decode byte stream
|
|||
index int // read point
|
|||
|
|||
deterministic bool |
|||
} |
|||
|
|||
// NewBuffer allocates a new Buffer and initializes its internal data to
|
|||
// the contents of the argument slice.
|
|||
func NewBuffer(e []byte) *Buffer { |
|||
return &Buffer{buf: e} |
|||
} |
|||
|
|||
// Reset resets the Buffer, ready for marshaling a new protocol buffer.
|
|||
func (p *Buffer) Reset() { |
|||
p.buf = p.buf[0:0] // for reading/writing
|
|||
p.index = 0 // for reading
|
|||
} |
|||
|
|||
// SetBuf replaces the internal buffer with the slice,
|
|||
// ready for unmarshaling the contents of the slice.
|
|||
func (p *Buffer) SetBuf(s []byte) { |
|||
p.buf = s |
|||
p.index = 0 |
|||
} |
|||
|
|||
// Bytes returns the contents of the Buffer.
|
|||
func (p *Buffer) Bytes() []byte { return p.buf } |
|||
|
|||
// SetDeterministic sets whether to use deterministic serialization.
|
|||
//
|
|||
// Deterministic serialization guarantees that for a given binary, equal
|
|||
// messages will always be serialized to the same bytes. This implies:
|
|||
//
|
|||
// - Repeated serialization of a message will return the same bytes.
|
|||
// - Different processes of the same binary (which may be executing on
|
|||
// different machines) will serialize equal messages to the same bytes.
|
|||
//
|
|||
// Note that the deterministic serialization is NOT canonical across
|
|||
// languages. It is not guaranteed to remain stable over time. It is unstable
|
|||
// across different builds with schema changes due to unknown fields.
|
|||
// Users who need canonical serialization (e.g., persistent storage in a
|
|||
// canonical form, fingerprinting, etc.) should define their own
|
|||
// canonicalization specification and implement their own serializer rather
|
|||
// than relying on this API.
|
|||
//
|
|||
// If deterministic serialization is requested, map entries will be sorted
|
|||
// by keys in lexicographical order. This is an implementation detail and
|
|||
// subject to change.
|
|||
func (p *Buffer) SetDeterministic(deterministic bool) { |
|||
p.deterministic = deterministic |
|||
} |
|||
|
|||
/* |
|||
* Helper routines for simplifying the creation of optional fields of basic type. |
|||
*/ |
|||
|
|||
// Bool is a helper routine that allocates a new bool value
|
|||
// to store v and returns a pointer to it.
|
|||
func Bool(v bool) *bool { |
|||
return &v |
|||
} |
|||
|
|||
// Int32 is a helper routine that allocates a new int32 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Int32(v int32) *int32 { |
|||
return &v |
|||
} |
|||
|
|||
// Int is a helper routine that allocates a new int32 value
|
|||
// to store v and returns a pointer to it, but unlike Int32
|
|||
// its argument value is an int.
|
|||
func Int(v int) *int32 { |
|||
p := new(int32) |
|||
*p = int32(v) |
|||
return p |
|||
} |
|||
|
|||
// Int64 is a helper routine that allocates a new int64 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Int64(v int64) *int64 { |
|||
return &v |
|||
} |
|||
|
|||
// Float32 is a helper routine that allocates a new float32 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Float32(v float32) *float32 { |
|||
return &v |
|||
} |
|||
|
|||
// Float64 is a helper routine that allocates a new float64 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Float64(v float64) *float64 { |
|||
return &v |
|||
} |
|||
|
|||
// Uint32 is a helper routine that allocates a new uint32 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Uint32(v uint32) *uint32 { |
|||
return &v |
|||
} |
|||
|
|||
// Uint64 is a helper routine that allocates a new uint64 value
|
|||
// to store v and returns a pointer to it.
|
|||
func Uint64(v uint64) *uint64 { |
|||
return &v |
|||
} |
|||
|
|||
// String is a helper routine that allocates a new string value
|
|||
// to store v and returns a pointer to it.
|
|||
func String(v string) *string { |
|||
return &v |
|||
} |
|||
|
|||
// EnumName is a helper function to simplify printing protocol buffer enums
|
|||
// by name. Given an enum map and a value, it returns a useful string.
|
|||
func EnumName(m map[int32]string, v int32) string { |
|||
s, ok := m[v] |
|||
if ok { |
|||
return s |
|||
} |
|||
return strconv.Itoa(int(v)) |
|||
} |
|||
|
|||
// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
|
|||
// from their JSON-encoded representation. Given a map from the enum's symbolic
|
|||
// names to its int values, and a byte buffer containing the JSON-encoded
|
|||
// value, it returns an int32 that can be cast to the enum type by the caller.
|
|||
//
|
|||
// The function can deal with both JSON representations, numeric and symbolic.
|
|||
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { |
|||
if data[0] == '"' { |
|||
// New style: enums are strings.
|
|||
var repr string |
|||
if err := json.Unmarshal(data, &repr); err != nil { |
|||
return -1, err |
|||
} |
|||
val, ok := m[repr] |
|||
if !ok { |
|||
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) |
|||
} |
|||
return val, nil |
|||
} |
|||
// Old style: enums are ints.
|
|||
var val int32 |
|||
if err := json.Unmarshal(data, &val); err != nil { |
|||
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) |
|||
} |
|||
return val, nil |
|||
} |
|||
|
|||
// DebugPrint dumps the encoded data in b in a debugging format with a header
|
|||
// including the string s. Used in testing but made available for general debugging.
|
|||
func (p *Buffer) DebugPrint(s string, b []byte) { |
|||
var u uint64 |
|||
|
|||
obuf := p.buf |
|||
index := p.index |
|||
p.buf = b |
|||
p.index = 0 |
|||
depth := 0 |
|||
|
|||
fmt.Printf("\n--- %s ---\n", s) |
|||
|
|||
out: |
|||
for { |
|||
for i := 0; i < depth; i++ { |
|||
fmt.Print(" ") |
|||
} |
|||
|
|||
index := p.index |
|||
if index == len(p.buf) { |
|||
break |
|||
} |
|||
|
|||
op, err := p.DecodeVarint() |
|||
if err != nil { |
|||
fmt.Printf("%3d: fetching op err %v\n", index, err) |
|||
break out |
|||
} |
|||
tag := op >> 3 |
|||
wire := op & 7 |
|||
|
|||
switch wire { |
|||
default: |
|||
fmt.Printf("%3d: t=%3d unknown wire=%d\n", |
|||
index, tag, wire) |
|||
break out |
|||
|
|||
case WireBytes: |
|||
var r []byte |
|||
|
|||
r, err = p.DecodeRawBytes(false) |
|||
if err != nil { |
|||
break out |
|||
} |
|||
fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) |
|||
if len(r) <= 6 { |
|||
for i := 0; i < len(r); i++ { |
|||
fmt.Printf(" %.2x", r[i]) |
|||
} |
|||
} else { |
|||
for i := 0; i < 3; i++ { |
|||
fmt.Printf(" %.2x", r[i]) |
|||
} |
|||
fmt.Printf(" ..") |
|||
for i := len(r) - 3; i < len(r); i++ { |
|||
fmt.Printf(" %.2x", r[i]) |
|||
} |
|||
} |
|||
fmt.Printf("\n") |
|||
|
|||
case WireFixed32: |
|||
u, err = p.DecodeFixed32() |
|||
if err != nil { |
|||
fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) |
|||
break out |
|||
} |
|||
fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) |
|||
|
|||
case WireFixed64: |
|||
u, err = p.DecodeFixed64() |
|||
if err != nil { |
|||
fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) |
|||
break out |
|||
} |
|||
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) |
|||
|
|||
case WireVarint: |
|||
u, err = p.DecodeVarint() |
|||
if err != nil { |
|||
fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) |
|||
break out |
|||
} |
|||
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) |
|||
|
|||
case WireStartGroup: |
|||
fmt.Printf("%3d: t=%3d start\n", index, tag) |
|||
depth++ |
|||
|
|||
case WireEndGroup: |
|||
depth-- |
|||
fmt.Printf("%3d: t=%3d end\n", index, tag) |
|||
} |
|||
} |
|||
|
|||
if depth != 0 { |
|||
fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) |
|||
} |
|||
fmt.Printf("\n") |
|||
|
|||
p.buf = obuf |
|||
p.index = index |
|||
} |
|||
|
|||
// SetDefaults sets unset protocol buffer fields to their default values.
|
|||
// It only modifies fields that are both unset and have defined defaults.
|
|||
// It recursively sets default values in any non-nil sub-messages.
|
|||
func SetDefaults(pb Message) { |
|||
setDefaults(reflect.ValueOf(pb), true, false) |
|||
} |
|||
|
|||
// v is a pointer to a struct.
|
|||
func setDefaults(v reflect.Value, recur, zeros bool) { |
|||
v = v.Elem() |
|||
|
|||
defaultMu.RLock() |
|||
dm, ok := defaults[v.Type()] |
|||
defaultMu.RUnlock() |
|||
if !ok { |
|||
dm = buildDefaultMessage(v.Type()) |
|||
defaultMu.Lock() |
|||
defaults[v.Type()] = dm |
|||
defaultMu.Unlock() |
|||
} |
|||
|
|||
for _, sf := range dm.scalars { |
|||
f := v.Field(sf.index) |
|||
if !f.IsNil() { |
|||
// field already set
|
|||
continue |
|||
} |
|||
dv := sf.value |
|||
if dv == nil && !zeros { |
|||
// no explicit default, and don't want to set zeros
|
|||
continue |
|||
} |
|||
fptr := f.Addr().Interface() // **T
|
|||
// TODO: Consider batching the allocations we do here.
|
|||
switch sf.kind { |
|||
case reflect.Bool: |
|||
b := new(bool) |
|||
if dv != nil { |
|||
*b = dv.(bool) |
|||
} |
|||
*(fptr.(**bool)) = b |
|||
case reflect.Float32: |
|||
f := new(float32) |
|||
if dv != nil { |
|||
*f = dv.(float32) |
|||
} |
|||
*(fptr.(**float32)) = f |
|||
case reflect.Float64: |
|||
f := new(float64) |
|||
if dv != nil { |
|||
*f = dv.(float64) |
|||
} |
|||
*(fptr.(**float64)) = f |
|||
case reflect.Int32: |
|||
// might be an enum
|
|||
if ft := f.Type(); ft != int32PtrType { |
|||
// enum
|
|||
f.Set(reflect.New(ft.Elem())) |
|||
if dv != nil { |
|||
f.Elem().SetInt(int64(dv.(int32))) |
|||
} |
|||
} else { |
|||
// int32 field
|
|||
i := new(int32) |
|||
if dv != nil { |
|||
*i = dv.(int32) |
|||
} |
|||
*(fptr.(**int32)) = i |
|||
} |
|||
case reflect.Int64: |
|||
i := new(int64) |
|||
if dv != nil { |
|||
*i = dv.(int64) |
|||
} |
|||
*(fptr.(**int64)) = i |
|||
case reflect.String: |
|||
s := new(string) |
|||
if dv != nil { |
|||
*s = dv.(string) |
|||
} |
|||
*(fptr.(**string)) = s |
|||
case reflect.Uint8: |
|||
// exceptional case: []byte
|
|||
var b []byte |
|||
if dv != nil { |
|||
db := dv.([]byte) |
|||
b = make([]byte, len(db)) |
|||
copy(b, db) |
|||
} else { |
|||
b = []byte{} |
|||
} |
|||
*(fptr.(*[]byte)) = b |
|||
case reflect.Uint32: |
|||
u := new(uint32) |
|||
if dv != nil { |
|||
*u = dv.(uint32) |
|||
} |
|||
*(fptr.(**uint32)) = u |
|||
case reflect.Uint64: |
|||
u := new(uint64) |
|||
if dv != nil { |
|||
*u = dv.(uint64) |
|||
} |
|||
*(fptr.(**uint64)) = u |
|||
default: |
|||
log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) |
|||
} |
|||
} |
|||
|
|||
for _, ni := range dm.nested { |
|||
f := v.Field(ni) |
|||
// f is *T or []*T or map[T]*T
|
|||
switch f.Kind() { |
|||
case reflect.Ptr: |
|||
if f.IsNil() { |
|||
continue |
|||
} |
|||
setDefaults(f, recur, zeros) |
|||
|
|||
case reflect.Slice: |
|||
for i := 0; i < f.Len(); i++ { |
|||
e := f.Index(i) |
|||
if e.IsNil() { |
|||
continue |
|||
} |
|||
setDefaults(e, recur, zeros) |
|||
} |
|||
|
|||
case reflect.Map: |
|||
for _, k := range f.MapKeys() { |
|||
e := f.MapIndex(k) |
|||
if e.IsNil() { |
|||
continue |
|||
} |
|||
setDefaults(e, recur, zeros) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
var ( |
|||
// defaults maps a protocol buffer struct type to a slice of the fields,
|
|||
// with its scalar fields set to their proto-declared non-zero default values.
|
|||
defaultMu sync.RWMutex |
|||
defaults = make(map[reflect.Type]defaultMessage) |
|||
|
|||
int32PtrType = reflect.TypeOf((*int32)(nil)) |
|||
) |
|||
|
|||
// defaultMessage represents information about the default values of a message.
|
|||
type defaultMessage struct { |
|||
scalars []scalarField |
|||
nested []int // struct field index of nested messages
|
|||
} |
|||
|
|||
type scalarField struct { |
|||
index int // struct field index
|
|||
kind reflect.Kind // element type (the T in *T or []T)
|
|||
value interface{} // the proto-declared default value, or nil
|
|||
} |
|||
|
|||
// t is a struct type.
|
|||
func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { |
|||
sprop := GetProperties(t) |
|||
for _, prop := range sprop.Prop { |
|||
fi, ok := sprop.decoderTags.get(prop.Tag) |
|||
if !ok { |
|||
// XXX_unrecognized
|
|||
continue |
|||
} |
|||
ft := t.Field(fi).Type |
|||
|
|||
sf, nested, err := fieldDefault(ft, prop) |
|||
switch { |
|||
case err != nil: |
|||
log.Print(err) |
|||
case nested: |
|||
dm.nested = append(dm.nested, fi) |
|||
case sf != nil: |
|||
sf.index = fi |
|||
dm.scalars = append(dm.scalars, *sf) |
|||
} |
|||
} |
|||
|
|||
return dm |
|||
} |
|||
|
|||
// fieldDefault returns the scalarField for field type ft.
|
|||
// sf will be nil if the field can not have a default.
|
|||
// nestedMessage will be true if this is a nested message.
|
|||
// Note that sf.index is not set on return.
|
|||
func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { |
|||
var canHaveDefault bool |
|||
switch ft.Kind() { |
|||
case reflect.Ptr: |
|||
if ft.Elem().Kind() == reflect.Struct { |
|||
nestedMessage = true |
|||
} else { |
|||
canHaveDefault = true // proto2 scalar field
|
|||
} |
|||
|
|||
case reflect.Slice: |
|||
switch ft.Elem().Kind() { |
|||
case reflect.Ptr: |
|||
nestedMessage = true // repeated message
|
|||
case reflect.Uint8: |
|||
canHaveDefault = true // bytes field
|
|||
} |
|||
|
|||
case reflect.Map: |
|||
if ft.Elem().Kind() == reflect.Ptr { |
|||
nestedMessage = true // map with message values
|
|||
} |
|||
} |
|||
|
|||
if !canHaveDefault { |
|||
if nestedMessage { |
|||
return nil, true, nil |
|||
} |
|||
return nil, false, nil |
|||
} |
|||
|
|||
// We now know that ft is a pointer or slice.
|
|||
sf = &scalarField{kind: ft.Elem().Kind()} |
|||
|
|||
// scalar fields without defaults
|
|||
if !prop.HasDefault { |
|||
return sf, false, nil |
|||
} |
|||
|
|||
// a scalar field: either *T or []byte
|
|||
switch ft.Elem().Kind() { |
|||
case reflect.Bool: |
|||
x, err := strconv.ParseBool(prop.Default) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = x |
|||
case reflect.Float32: |
|||
x, err := strconv.ParseFloat(prop.Default, 32) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = float32(x) |
|||
case reflect.Float64: |
|||
x, err := strconv.ParseFloat(prop.Default, 64) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = x |
|||
case reflect.Int32: |
|||
x, err := strconv.ParseInt(prop.Default, 10, 32) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = int32(x) |
|||
case reflect.Int64: |
|||
x, err := strconv.ParseInt(prop.Default, 10, 64) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = x |
|||
case reflect.String: |
|||
sf.value = prop.Default |
|||
case reflect.Uint8: |
|||
// []byte (not *uint8)
|
|||
sf.value = []byte(prop.Default) |
|||
case reflect.Uint32: |
|||
x, err := strconv.ParseUint(prop.Default, 10, 32) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = uint32(x) |
|||
case reflect.Uint64: |
|||
x, err := strconv.ParseUint(prop.Default, 10, 64) |
|||
if err != nil { |
|||
return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) |
|||
} |
|||
sf.value = x |
|||
default: |
|||
return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) |
|||
} |
|||
|
|||
return sf, false, nil |
|||
} |
|||
|
|||
// mapKeys returns a sort.Interface to be used for sorting the map keys.
|
|||
// Map fields may have key types of non-float scalars, strings and enums.
|
|||
func mapKeys(vs []reflect.Value) sort.Interface { |
|||
s := mapKeySorter{vs: vs} |
|||
|
|||
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
|
|||
if len(vs) == 0 { |
|||
return s |
|||
} |
|||
switch vs[0].Kind() { |
|||
case reflect.Int32, reflect.Int64: |
|||
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } |
|||
case reflect.Uint32, reflect.Uint64: |
|||
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } |
|||
case reflect.Bool: |
|||
s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
|
|||
case reflect.String: |
|||
s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } |
|||
default: |
|||
panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) |
|||
} |
|||
|
|||
return s |
|||
} |
|||
|
|||
type mapKeySorter struct { |
|||
vs []reflect.Value |
|||
less func(a, b reflect.Value) bool |
|||
} |
|||
|
|||
func (s mapKeySorter) Len() int { return len(s.vs) } |
|||
func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } |
|||
func (s mapKeySorter) Less(i, j int) bool { |
|||
return s.less(s.vs[i], s.vs[j]) |
|||
} |
|||
|
|||
// isProto3Zero reports whether v is a zero proto3 value.
|
|||
func isProto3Zero(v reflect.Value) bool { |
|||
switch v.Kind() { |
|||
case reflect.Bool: |
|||
return !v.Bool() |
|||
case reflect.Int32, reflect.Int64: |
|||
return v.Int() == 0 |
|||
case reflect.Uint32, reflect.Uint64: |
|||
return v.Uint() == 0 |
|||
case reflect.Float32, reflect.Float64: |
|||
return v.Float() == 0 |
|||
case reflect.String: |
|||
return v.String() == "" |
|||
} |
|||
return false |
|||
} |
|||
|
|||
const ( |
|||
// ProtoPackageIsVersion3 is referenced from generated protocol buffer files
|
|||
// to assert that that code is compatible with this version of the proto package.
|
|||
ProtoPackageIsVersion3 = true |
|||
|
|||
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
|
|||
// to assert that that code is compatible with this version of the proto package.
|
|||
ProtoPackageIsVersion2 = true |
|||
|
|||
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
|||
// to assert that that code is compatible with this version of the proto package.
|
|||
ProtoPackageIsVersion1 = true |
|||
) |
|||
|
|||
// InternalMessageInfo is a type used internally by generated .pb.go files.
|
|||
// This type is not intended to be used by non-generated code.
|
|||
// This type is not subject to any compatibility guarantee.
|
|||
type InternalMessageInfo struct { |
|||
marshal *marshalInfo |
|||
unmarshal *unmarshalInfo |
|||
merge *mergeInfo |
|||
discard *discardInfo |
|||
} |
@ -0,0 +1,181 @@ |
|||
// 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 |
|||
|
|||
/* |
|||
* Support for message sets. |
|||
*/ |
|||
|
|||
import ( |
|||
"errors" |
|||
) |
|||
|
|||
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
|||
// A message type ID is required for storing a protocol buffer in a message set.
|
|||
var errNoMessageTypeID = errors.New("proto does not have a message type ID") |
|||
|
|||
// The first two types (_MessageSet_Item and messageSet)
|
|||
// model what the protocol compiler produces for the following protocol message:
|
|||
// message MessageSet {
|
|||
// repeated group Item = 1 {
|
|||
// required int32 type_id = 2;
|
|||
// required string message = 3;
|
|||
// };
|
|||
// }
|
|||
// That is the MessageSet wire format. We can't use a proto to generate these
|
|||
// because that would introduce a circular dependency between it and this package.
|
|||
|
|||
type _MessageSet_Item struct { |
|||
TypeId *int32 `protobuf:"varint,2,req,name=type_id"` |
|||
Message []byte `protobuf:"bytes,3,req,name=message"` |
|||
} |
|||
|
|||
type messageSet struct { |
|||
Item []*_MessageSet_Item `protobuf:"group,1,rep"` |
|||
XXX_unrecognized []byte |
|||
// TODO: caching?
|
|||
} |
|||
|
|||
// Make sure messageSet is a Message.
|
|||
var _ Message = (*messageSet)(nil) |
|||
|
|||
// messageTypeIder is an interface satisfied by a protocol buffer type
|
|||
// that may be stored in a MessageSet.
|
|||
type messageTypeIder interface { |
|||
MessageTypeId() int32 |
|||
} |
|||
|
|||
func (ms *messageSet) find(pb Message) *_MessageSet_Item { |
|||
mti, ok := pb.(messageTypeIder) |
|||
if !ok { |
|||
return nil |
|||
} |
|||
id := mti.MessageTypeId() |
|||
for _, item := range ms.Item { |
|||
if *item.TypeId == id { |
|||
return item |
|||
} |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (ms *messageSet) Has(pb Message) bool { |
|||
return ms.find(pb) != nil |
|||
} |
|||
|
|||
func (ms *messageSet) Unmarshal(pb Message) error { |
|||
if item := ms.find(pb); item != nil { |
|||
return Unmarshal(item.Message, pb) |
|||
} |
|||
if _, ok := pb.(messageTypeIder); !ok { |
|||
return errNoMessageTypeID |
|||
} |
|||
return nil // TODO: return error instead?
|
|||
} |
|||
|
|||
func (ms *messageSet) Marshal(pb Message) error { |
|||
msg, err := Marshal(pb) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if item := ms.find(pb); item != nil { |
|||
// reuse existing item
|
|||
item.Message = msg |
|||
return nil |
|||
} |
|||
|
|||
mti, ok := pb.(messageTypeIder) |
|||
if !ok { |
|||
return errNoMessageTypeID |
|||
} |
|||
|
|||
mtid := mti.MessageTypeId() |
|||
ms.Item = append(ms.Item, &_MessageSet_Item{ |
|||
TypeId: &mtid, |
|||
Message: msg, |
|||
}) |
|||
return nil |
|||
} |
|||
|
|||
func (ms *messageSet) Reset() { *ms = messageSet{} } |
|||
func (ms *messageSet) String() string { return CompactTextString(ms) } |
|||
func (*messageSet) ProtoMessage() {} |
|||
|
|||
// Support for the message_set_wire_format message option.
|
|||
|
|||
func skipVarint(buf []byte) []byte { |
|||
i := 0 |
|||
for ; buf[i]&0x80 != 0; i++ { |
|||
} |
|||
return buf[i+1:] |
|||
} |
|||
|
|||
// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
|||
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
|||
func unmarshalMessageSet(buf []byte, exts interface{}) error { |
|||
var m map[int32]Extension |
|||
switch exts := exts.(type) { |
|||
case *XXX_InternalExtensions: |
|||
m = exts.extensionsWrite() |
|||
case map[int32]Extension: |
|||
m = exts |
|||
default: |
|||
return errors.New("proto: not an extension map") |
|||
} |
|||
|
|||
ms := new(messageSet) |
|||
if err := Unmarshal(buf, ms); err != nil { |
|||
return err |
|||
} |
|||
for _, item := range ms.Item { |
|||
id := *item.TypeId |
|||
msg := item.Message |
|||
|
|||
// Restore wire type and field number varint, plus length varint.
|
|||
// Be careful to preserve duplicate items.
|
|||
b := EncodeVarint(uint64(id)<<3 | WireBytes) |
|||
if ext, ok := m[id]; ok { |
|||
// Existing data; rip off the tag and length varint
|
|||
// so we join the new data correctly.
|
|||
// We can assume that ext.enc is set because we are unmarshaling.
|
|||
o := ext.enc[len(b):] // skip wire type and field number
|
|||
_, n := DecodeVarint(o) // calculate length of length varint
|
|||
o = o[n:] // skip length varint
|
|||
msg = append(o, msg...) // join old data and new data
|
|||
} |
|||
b = append(b, EncodeVarint(uint64(len(msg)))...) |
|||
b = append(b, msg...) |
|||
|
|||
m[id] = Extension{enc: b} |
|||
} |
|||
return nil |
|||
} |
@ -0,0 +1,360 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2012 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.
|
|||
|
|||
// +build purego appengine js
|
|||
|
|||
// This file contains an implementation of proto field accesses using package reflect.
|
|||
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
|
|||
// be used on App Engine.
|
|||
|
|||
package proto |
|||
|
|||
import ( |
|||
"reflect" |
|||
"sync" |
|||
) |
|||
|
|||
const unsafeAllowed = false |
|||
|
|||
// A field identifies a field in a struct, accessible from a pointer.
|
|||
// In this implementation, a field is identified by the sequence of field indices
|
|||
// passed to reflect's FieldByIndex.
|
|||
type field []int |
|||
|
|||
// toField returns a field equivalent to the given reflect field.
|
|||
func toField(f *reflect.StructField) field { |
|||
return f.Index |
|||
} |
|||
|
|||
// invalidField is an invalid field identifier.
|
|||
var invalidField = field(nil) |
|||
|
|||
// zeroField is a noop when calling pointer.offset.
|
|||
var zeroField = field([]int{}) |
|||
|
|||
// IsValid reports whether the field identifier is valid.
|
|||
func (f field) IsValid() bool { return f != nil } |
|||
|
|||
// The pointer type is for the table-driven decoder.
|
|||
// The implementation here uses a reflect.Value of pointer type to
|
|||
// create a generic pointer. In pointer_unsafe.go we use unsafe
|
|||
// instead of reflect to implement the same (but faster) interface.
|
|||
type pointer struct { |
|||
v reflect.Value |
|||
} |
|||
|
|||
// toPointer converts an interface of pointer type to a pointer
|
|||
// that points to the same target.
|
|||
func toPointer(i *Message) pointer { |
|||
return pointer{v: reflect.ValueOf(*i)} |
|||
} |
|||
|
|||
// toAddrPointer converts an interface to a pointer that points to
|
|||
// the interface data.
|
|||
func toAddrPointer(i *interface{}, isptr, deref bool) pointer { |
|||
v := reflect.ValueOf(*i) |
|||
u := reflect.New(v.Type()) |
|||
u.Elem().Set(v) |
|||
if deref { |
|||
u = u.Elem() |
|||
} |
|||
return pointer{v: u} |
|||
} |
|||
|
|||
// valToPointer converts v to a pointer. v must be of pointer type.
|
|||
func valToPointer(v reflect.Value) pointer { |
|||
return pointer{v: v} |
|||
} |
|||
|
|||
// offset converts from a pointer to a structure to a pointer to
|
|||
// one of its fields.
|
|||
func (p pointer) offset(f field) pointer { |
|||
return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} |
|||
} |
|||
|
|||
func (p pointer) isNil() bool { |
|||
return p.v.IsNil() |
|||
} |
|||
|
|||
// grow updates the slice s in place to make it one element longer.
|
|||
// s must be addressable.
|
|||
// Returns the (addressable) new element.
|
|||
func grow(s reflect.Value) reflect.Value { |
|||
n, m := s.Len(), s.Cap() |
|||
if n < m { |
|||
s.SetLen(n + 1) |
|||
} else { |
|||
s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) |
|||
} |
|||
return s.Index(n) |
|||
} |
|||
|
|||
func (p pointer) toInt64() *int64 { |
|||
return p.v.Interface().(*int64) |
|||
} |
|||
func (p pointer) toInt64Ptr() **int64 { |
|||
return p.v.Interface().(**int64) |
|||
} |
|||
func (p pointer) toInt64Slice() *[]int64 { |
|||
return p.v.Interface().(*[]int64) |
|||
} |
|||
|
|||
var int32ptr = reflect.TypeOf((*int32)(nil)) |
|||
|
|||
func (p pointer) toInt32() *int32 { |
|||
return p.v.Convert(int32ptr).Interface().(*int32) |
|||
} |
|||
|
|||
// The toInt32Ptr/Slice methods don't work because of enums.
|
|||
// Instead, we must use set/get methods for the int32ptr/slice case.
|
|||
/* |
|||
func (p pointer) toInt32Ptr() **int32 { |
|||
return p.v.Interface().(**int32) |
|||
} |
|||
func (p pointer) toInt32Slice() *[]int32 { |
|||
return p.v.Interface().(*[]int32) |
|||
} |
|||
*/ |
|||
func (p pointer) getInt32Ptr() *int32 { |
|||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { |
|||
// raw int32 type
|
|||
return p.v.Elem().Interface().(*int32) |
|||
} |
|||
// an enum
|
|||
return p.v.Elem().Convert(int32PtrType).Interface().(*int32) |
|||
} |
|||
func (p pointer) setInt32Ptr(v int32) { |
|||
// Allocate value in a *int32. Possibly convert that to a *enum.
|
|||
// Then assign it to a **int32 or **enum.
|
|||
// Note: we can convert *int32 to *enum, but we can't convert
|
|||
// **int32 to **enum!
|
|||
p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) |
|||
} |
|||
|
|||
// getInt32Slice copies []int32 from p as a new slice.
|
|||
// This behavior differs from the implementation in pointer_unsafe.go.
|
|||
func (p pointer) getInt32Slice() []int32 { |
|||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { |
|||
// raw int32 type
|
|||
return p.v.Elem().Interface().([]int32) |
|||
} |
|||
// an enum
|
|||
// Allocate a []int32, then assign []enum's values into it.
|
|||
// Note: we can't convert []enum to []int32.
|
|||
slice := p.v.Elem() |
|||
s := make([]int32, slice.Len()) |
|||
for i := 0; i < slice.Len(); i++ { |
|||
s[i] = int32(slice.Index(i).Int()) |
|||
} |
|||
return s |
|||
} |
|||
|
|||
// setInt32Slice copies []int32 into p as a new slice.
|
|||
// This behavior differs from the implementation in pointer_unsafe.go.
|
|||
func (p pointer) setInt32Slice(v []int32) { |
|||
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { |
|||
// raw int32 type
|
|||
p.v.Elem().Set(reflect.ValueOf(v)) |
|||
return |
|||
} |
|||
// an enum
|
|||
// Allocate a []enum, then assign []int32's values into it.
|
|||
// Note: we can't convert []enum to []int32.
|
|||
slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) |
|||
for i, x := range v { |
|||
slice.Index(i).SetInt(int64(x)) |
|||
} |
|||
p.v.Elem().Set(slice) |
|||
} |
|||
func (p pointer) appendInt32Slice(v int32) { |
|||
grow(p.v.Elem()).SetInt(int64(v)) |
|||
} |
|||
|
|||
func (p pointer) toUint64() *uint64 { |
|||
return p.v.Interface().(*uint64) |
|||
} |
|||
func (p pointer) toUint64Ptr() **uint64 { |
|||
return p.v.Interface().(**uint64) |
|||
} |
|||
func (p pointer) toUint64Slice() *[]uint64 { |
|||
return p.v.Interface().(*[]uint64) |
|||
} |
|||
func (p pointer) toUint32() *uint32 { |
|||
return p.v.Interface().(*uint32) |
|||
} |
|||
func (p pointer) toUint32Ptr() **uint32 { |
|||
return p.v.Interface().(**uint32) |
|||
} |
|||
func (p pointer) toUint32Slice() *[]uint32 { |
|||
return p.v.Interface().(*[]uint32) |
|||
} |
|||
func (p pointer) toBool() *bool { |
|||
return p.v.Interface().(*bool) |
|||
} |
|||
func (p pointer) toBoolPtr() **bool { |
|||
return p.v.Interface().(**bool) |
|||
} |
|||
func (p pointer) toBoolSlice() *[]bool { |
|||
return p.v.Interface().(*[]bool) |
|||
} |
|||
func (p pointer) toFloat64() *float64 { |
|||
return p.v.Interface().(*float64) |
|||
} |
|||
func (p pointer) toFloat64Ptr() **float64 { |
|||
return p.v.Interface().(**float64) |
|||
} |
|||
func (p pointer) toFloat64Slice() *[]float64 { |
|||
return p.v.Interface().(*[]float64) |
|||
} |
|||
func (p pointer) toFloat32() *float32 { |
|||
return p.v.Interface().(*float32) |
|||
} |
|||
func (p pointer) toFloat32Ptr() **float32 { |
|||
return p.v.Interface().(**float32) |
|||
} |
|||
func (p pointer) toFloat32Slice() *[]float32 { |
|||
return p.v.Interface().(*[]float32) |
|||
} |
|||
func (p pointer) toString() *string { |
|||
return p.v.Interface().(*string) |
|||
} |
|||
func (p pointer) toStringPtr() **string { |
|||
return p.v.Interface().(**string) |
|||
} |
|||
func (p pointer) toStringSlice() *[]string { |
|||
return p.v.Interface().(*[]string) |
|||
} |
|||
func (p pointer) toBytes() *[]byte { |
|||
return p.v.Interface().(*[]byte) |
|||
} |
|||
func (p pointer) toBytesSlice() *[][]byte { |
|||
return p.v.Interface().(*[][]byte) |
|||
} |
|||
func (p pointer) toExtensions() *XXX_InternalExtensions { |
|||
return p.v.Interface().(*XXX_InternalExtensions) |
|||
} |
|||
func (p pointer) toOldExtensions() *map[int32]Extension { |
|||
return p.v.Interface().(*map[int32]Extension) |
|||
} |
|||
func (p pointer) getPointer() pointer { |
|||
return pointer{v: p.v.Elem()} |
|||
} |
|||
func (p pointer) setPointer(q pointer) { |
|||
p.v.Elem().Set(q.v) |
|||
} |
|||
func (p pointer) appendPointer(q pointer) { |
|||
grow(p.v.Elem()).Set(q.v) |
|||
} |
|||
|
|||
// getPointerSlice copies []*T from p as a new []pointer.
|
|||
// This behavior differs from the implementation in pointer_unsafe.go.
|
|||
func (p pointer) getPointerSlice() []pointer { |
|||
if p.v.IsNil() { |
|||
return nil |
|||
} |
|||
n := p.v.Elem().Len() |
|||
s := make([]pointer, n) |
|||
for i := 0; i < n; i++ { |
|||
s[i] = pointer{v: p.v.Elem().Index(i)} |
|||
} |
|||
return s |
|||
} |
|||
|
|||
// setPointerSlice copies []pointer into p as a new []*T.
|
|||
// This behavior differs from the implementation in pointer_unsafe.go.
|
|||
func (p pointer) setPointerSlice(v []pointer) { |
|||
if v == nil { |
|||
p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) |
|||
return |
|||
} |
|||
s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) |
|||
for _, p := range v { |
|||
s = reflect.Append(s, p.v) |
|||
} |
|||
p.v.Elem().Set(s) |
|||
} |
|||
|
|||
// getInterfacePointer returns a pointer that points to the
|
|||
// interface data of the interface pointed by p.
|
|||
func (p pointer) getInterfacePointer() pointer { |
|||
if p.v.Elem().IsNil() { |
|||
return pointer{v: p.v.Elem()} |
|||
} |
|||
return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct
|
|||
} |
|||
|
|||
func (p pointer) asPointerTo(t reflect.Type) reflect.Value { |
|||
// TODO: check that p.v.Type().Elem() == t?
|
|||
return p.v |
|||
} |
|||
|
|||
func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
return *p |
|||
} |
|||
func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
*p = v |
|||
} |
|||
func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
return *p |
|||
} |
|||
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
*p = v |
|||
} |
|||
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
return *p |
|||
} |
|||
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
*p = v |
|||
} |
|||
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
return *p |
|||
} |
|||
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { |
|||
atomicLock.Lock() |
|||
defer atomicLock.Unlock() |
|||
*p = v |
|||
} |
|||
|
|||
var atomicLock sync.Mutex |
@ -0,0 +1,313 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2012 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.
|
|||
|
|||
// +build !purego,!appengine,!js
|
|||
|
|||
// This file contains the implementation of the proto field accesses using package unsafe.
|
|||
|
|||
package proto |
|||
|
|||
import ( |
|||
"reflect" |
|||
"sync/atomic" |
|||
"unsafe" |
|||
) |
|||
|
|||
const unsafeAllowed = true |
|||
|
|||
// A field identifies a field in a struct, accessible from a pointer.
|
|||
// In this implementation, a field is identified by its byte offset from the start of the struct.
|
|||
type field uintptr |
|||
|
|||
// toField returns a field equivalent to the given reflect field.
|
|||
func toField(f *reflect.StructField) field { |
|||
return field(f.Offset) |
|||
} |
|||
|
|||
// invalidField is an invalid field identifier.
|
|||
const invalidField = ^field(0) |
|||
|
|||
// zeroField is a noop when calling pointer.offset.
|
|||
const zeroField = field(0) |
|||
|
|||
// IsValid reports whether the field identifier is valid.
|
|||
func (f field) IsValid() bool { |
|||
return f != invalidField |
|||
} |
|||
|
|||
// The pointer type below is for the new table-driven encoder/decoder.
|
|||
// The implementation here uses unsafe.Pointer to create a generic pointer.
|
|||
// In pointer_reflect.go we use reflect instead of unsafe to implement
|
|||
// the same (but slower) interface.
|
|||
type pointer struct { |
|||
p unsafe.Pointer |
|||
} |
|||
|
|||
// size of pointer
|
|||
var ptrSize = unsafe.Sizeof(uintptr(0)) |
|||
|
|||
// toPointer converts an interface of pointer type to a pointer
|
|||
// that points to the same target.
|
|||
func toPointer(i *Message) pointer { |
|||
// Super-tricky - read pointer out of data word of interface value.
|
|||
// Saves ~25ns over the equivalent:
|
|||
// return valToPointer(reflect.ValueOf(*i))
|
|||
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} |
|||
} |
|||
|
|||
// toAddrPointer converts an interface to a pointer that points to
|
|||
// the interface data.
|
|||
func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { |
|||
// Super-tricky - read or get the address of data word of interface value.
|
|||
if isptr { |
|||
// The interface is of pointer type, thus it is a direct interface.
|
|||
// The data word is the pointer data itself. We take its address.
|
|||
p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} |
|||
} else { |
|||
// The interface is not of pointer type. The data word is the pointer
|
|||
// to the data.
|
|||
p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} |
|||
} |
|||
if deref { |
|||
p.p = *(*unsafe.Pointer)(p.p) |
|||
} |
|||
return p |
|||
} |
|||
|
|||
// valToPointer converts v to a pointer. v must be of pointer type.
|
|||
func valToPointer(v reflect.Value) pointer { |
|||
return pointer{p: unsafe.Pointer(v.Pointer())} |
|||
} |
|||
|
|||
// offset converts from a pointer to a structure to a pointer to
|
|||
// one of its fields.
|
|||
func (p pointer) offset(f field) pointer { |
|||
// For safety, we should panic if !f.IsValid, however calling panic causes
|
|||
// this to no longer be inlineable, which is a serious performance cost.
|
|||
/* |
|||
if !f.IsValid() { |
|||
panic("invalid field") |
|||
} |
|||
*/ |
|||
return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} |
|||
} |
|||
|
|||
func (p pointer) isNil() bool { |
|||
return p.p == nil |
|||
} |
|||
|
|||
func (p pointer) toInt64() *int64 { |
|||
return (*int64)(p.p) |
|||
} |
|||
func (p pointer) toInt64Ptr() **int64 { |
|||
return (**int64)(p.p) |
|||
} |
|||
func (p pointer) toInt64Slice() *[]int64 { |
|||
return (*[]int64)(p.p) |
|||
} |
|||
func (p pointer) toInt32() *int32 { |
|||
return (*int32)(p.p) |
|||
} |
|||
|
|||
// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist.
|
|||
/* |
|||
func (p pointer) toInt32Ptr() **int32 { |
|||
return (**int32)(p.p) |
|||
} |
|||
func (p pointer) toInt32Slice() *[]int32 { |
|||
return (*[]int32)(p.p) |
|||
} |
|||
*/ |
|||
func (p pointer) getInt32Ptr() *int32 { |
|||
return *(**int32)(p.p) |
|||
} |
|||
func (p pointer) setInt32Ptr(v int32) { |
|||
*(**int32)(p.p) = &v |
|||
} |
|||
|
|||
// getInt32Slice loads a []int32 from p.
|
|||
// The value returned is aliased with the original slice.
|
|||
// This behavior differs from the implementation in pointer_reflect.go.
|
|||
func (p pointer) getInt32Slice() []int32 { |
|||
return *(*[]int32)(p.p) |
|||
} |
|||
|
|||
// setInt32Slice stores a []int32 to p.
|
|||
// The value set is aliased with the input slice.
|
|||
// This behavior differs from the implementation in pointer_reflect.go.
|
|||
func (p pointer) setInt32Slice(v []int32) { |
|||
*(*[]int32)(p.p) = v |
|||
} |
|||
|
|||
// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead?
|
|||
func (p pointer) appendInt32Slice(v int32) { |
|||
s := (*[]int32)(p.p) |
|||
*s = append(*s, v) |
|||
} |
|||
|
|||
func (p pointer) toUint64() *uint64 { |
|||
return (*uint64)(p.p) |
|||
} |
|||
func (p pointer) toUint64Ptr() **uint64 { |
|||
return (**uint64)(p.p) |
|||
} |
|||
func (p pointer) toUint64Slice() *[]uint64 { |
|||
return (*[]uint64)(p.p) |
|||
} |
|||
func (p pointer) toUint32() *uint32 { |
|||
return (*uint32)(p.p) |
|||
} |
|||
func (p pointer) toUint32Ptr() **uint32 { |
|||
return (**uint32)(p.p) |
|||
} |
|||
func (p pointer) toUint32Slice() *[]uint32 { |
|||
return (*[]uint32)(p.p) |
|||
} |
|||
func (p pointer) toBool() *bool { |
|||
return (*bool)(p.p) |
|||
} |
|||
func (p pointer) toBoolPtr() **bool { |
|||
return (**bool)(p.p) |
|||
} |
|||
func (p pointer) toBoolSlice() *[]bool { |
|||
return (*[]bool)(p.p) |
|||
} |
|||
func (p pointer) toFloat64() *float64 { |
|||
return (*float64)(p.p) |
|||
} |
|||
func (p pointer) toFloat64Ptr() **float64 { |
|||
return (**float64)(p.p) |
|||
} |
|||
func (p pointer) toFloat64Slice() *[]float64 { |
|||
return (*[]float64)(p.p) |
|||
} |
|||
func (p pointer) toFloat32() *float32 { |
|||
return (*float32)(p.p) |
|||
} |
|||
func (p pointer) toFloat32Ptr() **float32 { |
|||
return (**float32)(p.p) |
|||
} |
|||
func (p pointer) toFloat32Slice() *[]float32 { |
|||
return (*[]float32)(p.p) |
|||
} |
|||
func (p pointer) toString() *string { |
|||
return (*string)(p.p) |
|||
} |
|||
func (p pointer) toStringPtr() **string { |
|||
return (**string)(p.p) |
|||
} |
|||
func (p pointer) toStringSlice() *[]string { |
|||
return (*[]string)(p.p) |
|||
} |
|||
func (p pointer) toBytes() *[]byte { |
|||
return (*[]byte)(p.p) |
|||
} |
|||
func (p pointer) toBytesSlice() *[][]byte { |
|||
return (*[][]byte)(p.p) |
|||
} |
|||
func (p pointer) toExtensions() *XXX_InternalExtensions { |
|||
return (*XXX_InternalExtensions)(p.p) |
|||
} |
|||
func (p pointer) toOldExtensions() *map[int32]Extension { |
|||
return (*map[int32]Extension)(p.p) |
|||
} |
|||
|
|||
// getPointerSlice loads []*T from p as a []pointer.
|
|||
// The value returned is aliased with the original slice.
|
|||
// This behavior differs from the implementation in pointer_reflect.go.
|
|||
func (p pointer) getPointerSlice() []pointer { |
|||
// Super-tricky - p should point to a []*T where T is a
|
|||
// message type. We load it as []pointer.
|
|||
return *(*[]pointer)(p.p) |
|||
} |
|||
|
|||
// setPointerSlice stores []pointer into p as a []*T.
|
|||
// The value set is aliased with the input slice.
|
|||
// This behavior differs from the implementation in pointer_reflect.go.
|
|||
func (p pointer) setPointerSlice(v []pointer) { |
|||
// Super-tricky - p should point to a []*T where T is a
|
|||
// message type. We store it as []pointer.
|
|||
*(*[]pointer)(p.p) = v |
|||
} |
|||
|
|||
// getPointer loads the pointer at p and returns it.
|
|||
func (p pointer) getPointer() pointer { |
|||
return pointer{p: *(*unsafe.Pointer)(p.p)} |
|||
} |
|||
|
|||
// setPointer stores the pointer q at p.
|
|||
func (p pointer) setPointer(q pointer) { |
|||
*(*unsafe.Pointer)(p.p) = q.p |
|||
} |
|||
|
|||
// append q to the slice pointed to by p.
|
|||
func (p pointer) appendPointer(q pointer) { |
|||
s := (*[]unsafe.Pointer)(p.p) |
|||
*s = append(*s, q.p) |
|||
} |
|||
|
|||
// getInterfacePointer returns a pointer that points to the
|
|||
// interface data of the interface pointed by p.
|
|||
func (p pointer) getInterfacePointer() pointer { |
|||
// Super-tricky - read pointer out of data word of interface value.
|
|||
return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} |
|||
} |
|||
|
|||
// asPointerTo returns a reflect.Value that is a pointer to an
|
|||
// object of type t stored at p.
|
|||
func (p pointer) asPointerTo(t reflect.Type) reflect.Value { |
|||
return reflect.NewAt(t, p.p) |
|||
} |
|||
|
|||
func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { |
|||
return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) |
|||
} |
|||
func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { |
|||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) |
|||
} |
|||
func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { |
|||
return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) |
|||
} |
|||
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { |
|||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) |
|||
} |
|||
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { |
|||
return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) |
|||
} |
|||
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { |
|||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) |
|||
} |
|||
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { |
|||
return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) |
|||
} |
|||
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { |
|||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) |
|||
} |
@ -0,0 +1,544 @@ |
|||
// 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 ( |
|||
"fmt" |
|||
"log" |
|||
"reflect" |
|||
"sort" |
|||
"strconv" |
|||
"strings" |
|||
"sync" |
|||
) |
|||
|
|||
const debug bool = false |
|||
|
|||
// Constants that identify the encoding of a value on the wire.
|
|||
const ( |
|||
WireVarint = 0 |
|||
WireFixed64 = 1 |
|||
WireBytes = 2 |
|||
WireStartGroup = 3 |
|||
WireEndGroup = 4 |
|||
WireFixed32 = 5 |
|||
) |
|||
|
|||
// tagMap is an optimization over map[int]int for typical protocol buffer
|
|||
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
|||
// numbers.
|
|||
type tagMap struct { |
|||
fastTags []int |
|||
slowTags map[int]int |
|||
} |
|||
|
|||
// tagMapFastLimit is the upper bound on the tag number that will be stored in
|
|||
// the tagMap slice rather than its map.
|
|||
const tagMapFastLimit = 1024 |
|||
|
|||
func (p *tagMap) get(t int) (int, bool) { |
|||
if t > 0 && t < tagMapFastLimit { |
|||
if t >= len(p.fastTags) { |
|||
return 0, false |
|||
} |
|||
fi := p.fastTags[t] |
|||
return fi, fi >= 0 |
|||
} |
|||
fi, ok := p.slowTags[t] |
|||
return fi, ok |
|||
} |
|||
|
|||
func (p *tagMap) put(t int, fi int) { |
|||
if t > 0 && t < tagMapFastLimit { |
|||
for len(p.fastTags) < t+1 { |
|||
p.fastTags = append(p.fastTags, -1) |
|||
} |
|||
p.fastTags[t] = fi |
|||
return |
|||
} |
|||
if p.slowTags == nil { |
|||
p.slowTags = make(map[int]int) |
|||
} |
|||
p.slowTags[t] = fi |
|||
} |
|||
|
|||
// StructProperties represents properties for all the fields of a struct.
|
|||
// decoderTags and decoderOrigNames should only be used by the decoder.
|
|||
type StructProperties struct { |
|||
Prop []*Properties // properties for each field
|
|||
reqCount int // required count
|
|||
decoderTags tagMap // map from proto tag to struct field number
|
|||
decoderOrigNames map[string]int // map from original name to struct field number
|
|||
order []int // list of struct field numbers in tag order
|
|||
|
|||
// OneofTypes contains information about the oneof fields in this message.
|
|||
// It is keyed by the original name of a field.
|
|||
OneofTypes map[string]*OneofProperties |
|||
} |
|||
|
|||
// OneofProperties represents information about a specific field in a oneof.
|
|||
type OneofProperties struct { |
|||
Type reflect.Type // pointer to generated struct type for this oneof field
|
|||
Field int // struct field number of the containing oneof in the message
|
|||
Prop *Properties |
|||
} |
|||
|
|||
// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
|
|||
// See encode.go, (*Buffer).enc_struct.
|
|||
|
|||
func (sp *StructProperties) Len() int { return len(sp.order) } |
|||
func (sp *StructProperties) Less(i, j int) bool { |
|||
return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag |
|||
} |
|||
func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } |
|||
|
|||
// Properties represents the protocol-specific behavior of a single struct field.
|
|||
type Properties struct { |
|||
Name string // name of the field, for error messages
|
|||
OrigName string // original name before protocol compiler (always set)
|
|||
JSONName string // name to use for JSON; determined by protoc
|
|||
Wire string |
|||
WireType int |
|||
Tag int |
|||
Required bool |
|||
Optional bool |
|||
Repeated bool |
|||
Packed bool // relevant for repeated primitives only
|
|||
Enum string // set for enum types only
|
|||
proto3 bool // whether this is known to be a proto3 field
|
|||
oneof bool // whether this is a oneof field
|
|||
|
|||
Default string // default value
|
|||
HasDefault bool // whether an explicit default was provided
|
|||
|
|||
stype reflect.Type // set for struct types only
|
|||
sprop *StructProperties // set for struct types only
|
|||
|
|||
mtype reflect.Type // set for map types only
|
|||
MapKeyProp *Properties // set for map types only
|
|||
MapValProp *Properties // set for map types only
|
|||
} |
|||
|
|||
// String formats the properties in the protobuf struct field tag style.
|
|||
func (p *Properties) String() string { |
|||
s := p.Wire |
|||
s += "," |
|||
s += strconv.Itoa(p.Tag) |
|||
if p.Required { |
|||
s += ",req" |
|||
} |
|||
if p.Optional { |
|||
s += ",opt" |
|||
} |
|||
if p.Repeated { |
|||
s += ",rep" |
|||
} |
|||
if p.Packed { |
|||
s += ",packed" |
|||
} |
|||
s += ",name=" + p.OrigName |
|||
if p.JSONName != p.OrigName { |
|||
s += ",json=" + p.JSONName |
|||
} |
|||
if p.proto3 { |
|||
s += ",proto3" |
|||
} |
|||
if p.oneof { |
|||
s += ",oneof" |
|||
} |
|||
if len(p.Enum) > 0 { |
|||
s += ",enum=" + p.Enum |
|||
} |
|||
if p.HasDefault { |
|||
s += ",def=" + p.Default |
|||
} |
|||
return s |
|||
} |
|||
|
|||
// Parse populates p by parsing a string in the protobuf struct field tag style.
|
|||
func (p *Properties) Parse(s string) { |
|||
// "bytes,49,opt,name=foo,def=hello!"
|
|||
fields := strings.Split(s, ",") // breaks def=, but handled below.
|
|||
if len(fields) < 2 { |
|||
log.Printf("proto: tag has too few fields: %q", s) |
|||
return |
|||
} |
|||
|
|||
p.Wire = fields[0] |
|||
switch p.Wire { |
|||
case "varint": |
|||
p.WireType = WireVarint |
|||
case "fixed32": |
|||
p.WireType = WireFixed32 |
|||
case "fixed64": |
|||
p.WireType = WireFixed64 |
|||
case "zigzag32": |
|||
p.WireType = WireVarint |
|||
case "zigzag64": |
|||
p.WireType = WireVarint |
|||
case "bytes", "group": |
|||
p.WireType = WireBytes |
|||
// no numeric converter for non-numeric types
|
|||
default: |
|||
log.Printf("proto: tag has unknown wire type: %q", s) |
|||
return |
|||
} |
|||
|
|||
var err error |
|||
p.Tag, err = strconv.Atoi(fields[1]) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
outer: |
|||
for i := 2; i < len(fields); i++ { |
|||
f := fields[i] |
|||
switch { |
|||
case f == "req": |
|||
p.Required = true |
|||
case f == "opt": |
|||
p.Optional = true |
|||
case f == "rep": |
|||
p.Repeated = true |
|||
case f == "packed": |
|||
p.Packed = true |
|||
case strings.HasPrefix(f, "name="): |
|||
p.OrigName = f[5:] |
|||
case strings.HasPrefix(f, "json="): |
|||
p.JSONName = f[5:] |
|||
case strings.HasPrefix(f, "enum="): |
|||
p.Enum = f[5:] |
|||
case f == "proto3": |
|||
p.proto3 = true |
|||
case f == "oneof": |
|||
p.oneof = true |
|||
case strings.HasPrefix(f, "def="): |
|||
p.HasDefault = true |
|||
p.Default = f[4:] // rest of string
|
|||
if i+1 < len(fields) { |
|||
// Commas aren't escaped, and def is always last.
|
|||
p.Default += "," + strings.Join(fields[i+1:], ",") |
|||
break outer |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() |
|||
|
|||
// setFieldProps initializes the field properties for submessages and maps.
|
|||
func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { |
|||
switch t1 := typ; t1.Kind() { |
|||
case reflect.Ptr: |
|||
if t1.Elem().Kind() == reflect.Struct { |
|||
p.stype = t1.Elem() |
|||
} |
|||
|
|||
case reflect.Slice: |
|||
if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { |
|||
p.stype = t2.Elem() |
|||
} |
|||
|
|||
case reflect.Map: |
|||
p.mtype = t1 |
|||
p.MapKeyProp = &Properties{} |
|||
p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) |
|||
p.MapValProp = &Properties{} |
|||
vtype := p.mtype.Elem() |
|||
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { |
|||
// The value type is not a message (*T) or bytes ([]byte),
|
|||
// so we need encoders for the pointer to this type.
|
|||
vtype = reflect.PtrTo(vtype) |
|||
} |
|||
p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) |
|||
} |
|||
|
|||
if p.stype != nil { |
|||
if lockGetProp { |
|||
p.sprop = GetProperties(p.stype) |
|||
} else { |
|||
p.sprop = getPropertiesLocked(p.stype) |
|||
} |
|||
} |
|||
} |
|||
|
|||
var ( |
|||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() |
|||
) |
|||
|
|||
// Init populates the properties from a protocol buffer struct tag.
|
|||
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { |
|||
p.init(typ, name, tag, f, true) |
|||
} |
|||
|
|||
func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { |
|||
// "bytes,49,opt,def=hello!"
|
|||
p.Name = name |
|||
p.OrigName = name |
|||
if tag == "" { |
|||
return |
|||
} |
|||
p.Parse(tag) |
|||
p.setFieldProps(typ, f, lockGetProp) |
|||
} |
|||
|
|||
var ( |
|||
propertiesMu sync.RWMutex |
|||
propertiesMap = make(map[reflect.Type]*StructProperties) |
|||
) |
|||
|
|||
// GetProperties returns the list of properties for the type represented by t.
|
|||
// t must represent a generated struct type of a protocol message.
|
|||
func GetProperties(t reflect.Type) *StructProperties { |
|||
if t.Kind() != reflect.Struct { |
|||
panic("proto: type must have kind struct") |
|||
} |
|||
|
|||
// Most calls to GetProperties in a long-running program will be
|
|||
// retrieving details for types we have seen before.
|
|||
propertiesMu.RLock() |
|||
sprop, ok := propertiesMap[t] |
|||
propertiesMu.RUnlock() |
|||
if ok { |
|||
return sprop |
|||
} |
|||
|
|||
propertiesMu.Lock() |
|||
sprop = getPropertiesLocked(t) |
|||
propertiesMu.Unlock() |
|||
return sprop |
|||
} |
|||
|
|||
type ( |
|||
oneofFuncsIface interface { |
|||
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) |
|||
} |
|||
oneofWrappersIface interface { |
|||
XXX_OneofWrappers() []interface{} |
|||
} |
|||
) |
|||
|
|||
// getPropertiesLocked requires that propertiesMu is held.
|
|||
func getPropertiesLocked(t reflect.Type) *StructProperties { |
|||
if prop, ok := propertiesMap[t]; ok { |
|||
return prop |
|||
} |
|||
|
|||
prop := new(StructProperties) |
|||
// in case of recursive protos, fill this in now.
|
|||
propertiesMap[t] = prop |
|||
|
|||
// build properties
|
|||
prop.Prop = make([]*Properties, t.NumField()) |
|||
prop.order = make([]int, t.NumField()) |
|||
|
|||
for i := 0; i < t.NumField(); i++ { |
|||
f := t.Field(i) |
|||
p := new(Properties) |
|||
name := f.Name |
|||
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) |
|||
|
|||
oneof := f.Tag.Get("protobuf_oneof") // special case
|
|||
if oneof != "" { |
|||
// Oneof fields don't use the traditional protobuf tag.
|
|||
p.OrigName = oneof |
|||
} |
|||
prop.Prop[i] = p |
|||
prop.order[i] = i |
|||
if debug { |
|||
print(i, " ", f.Name, " ", t.String(), " ") |
|||
if p.Tag > 0 { |
|||
print(p.String()) |
|||
} |
|||
print("\n") |
|||
} |
|||
} |
|||
|
|||
// Re-order prop.order.
|
|||
sort.Sort(prop) |
|||
|
|||
var oots []interface{} |
|||
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { |
|||
case oneofFuncsIface: |
|||
_, _, _, oots = m.XXX_OneofFuncs() |
|||
case oneofWrappersIface: |
|||
oots = m.XXX_OneofWrappers() |
|||
} |
|||
if len(oots) > 0 { |
|||
// Interpret oneof metadata.
|
|||
prop.OneofTypes = make(map[string]*OneofProperties) |
|||
for _, oot := range oots { |
|||
oop := &OneofProperties{ |
|||
Type: reflect.ValueOf(oot).Type(), // *T
|
|||
Prop: new(Properties), |
|||
} |
|||
sft := oop.Type.Elem().Field(0) |
|||
oop.Prop.Name = sft.Name |
|||
oop.Prop.Parse(sft.Tag.Get("protobuf")) |
|||
// There will be exactly one interface field that
|
|||
// this new value is assignable to.
|
|||
for i := 0; i < t.NumField(); i++ { |
|||
f := t.Field(i) |
|||
if f.Type.Kind() != reflect.Interface { |
|||
continue |
|||
} |
|||
if !oop.Type.AssignableTo(f.Type) { |
|||
continue |
|||
} |
|||
oop.Field = i |
|||
break |
|||
} |
|||
prop.OneofTypes[oop.Prop.OrigName] = oop |
|||
} |
|||
} |
|||
|
|||
// build required counts
|
|||
// build tags
|
|||
reqCount := 0 |
|||
prop.decoderOrigNames = make(map[string]int) |
|||
for i, p := range prop.Prop { |
|||
if strings.HasPrefix(p.Name, "XXX_") { |
|||
// Internal fields should not appear in tags/origNames maps.
|
|||
// They are handled specially when encoding and decoding.
|
|||
continue |
|||
} |
|||
if p.Required { |
|||
reqCount++ |
|||
} |
|||
prop.decoderTags.put(p.Tag, i) |
|||
prop.decoderOrigNames[p.OrigName] = i |
|||
} |
|||
prop.reqCount = reqCount |
|||
|
|||
return prop |
|||
} |
|||
|
|||
// A global registry of enum types.
|
|||
// The generated code will register the generated maps by calling RegisterEnum.
|
|||
|
|||
var enumValueMaps = make(map[string]map[string]int32) |
|||
|
|||
// RegisterEnum is called from the generated code to install the enum descriptor
|
|||
// maps into the global table to aid parsing text format protocol buffers.
|
|||
func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { |
|||
if _, ok := enumValueMaps[typeName]; ok { |
|||
panic("proto: duplicate enum registered: " + typeName) |
|||
} |
|||
enumValueMaps[typeName] = valueMap |
|||
} |
|||
|
|||
// EnumValueMap returns the mapping from names to integers of the
|
|||
// enum type enumType, or a nil if not found.
|
|||
func EnumValueMap(enumType string) map[string]int32 { |
|||
return enumValueMaps[enumType] |
|||
} |
|||
|
|||
// A registry of all linked message types.
|
|||
// The string is a fully-qualified proto name ("pkg.Message").
|
|||
var ( |
|||
protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers
|
|||
protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types
|
|||
revProtoTypes = make(map[reflect.Type]string) |
|||
) |
|||
|
|||
// RegisterType is called from generated code and maps from the fully qualified
|
|||
// proto name to the type (pointer to struct) of the protocol buffer.
|
|||
func RegisterType(x Message, name string) { |
|||
if _, ok := protoTypedNils[name]; ok { |
|||
// TODO: Some day, make this a panic.
|
|||
log.Printf("proto: duplicate proto type registered: %s", name) |
|||
return |
|||
} |
|||
t := reflect.TypeOf(x) |
|||
if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { |
|||
// Generated code always calls RegisterType with nil x.
|
|||
// This check is just for extra safety.
|
|||
protoTypedNils[name] = x |
|||
} else { |
|||
protoTypedNils[name] = reflect.Zero(t).Interface().(Message) |
|||
} |
|||
revProtoTypes[t] = name |
|||
} |
|||
|
|||
// RegisterMapType is called from generated code and maps from the fully qualified
|
|||
// proto name to the native map type of the proto map definition.
|
|||
func RegisterMapType(x interface{}, name string) { |
|||
if reflect.TypeOf(x).Kind() != reflect.Map { |
|||
panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) |
|||
} |
|||
if _, ok := protoMapTypes[name]; ok { |
|||
log.Printf("proto: duplicate proto type registered: %s", name) |
|||
return |
|||
} |
|||
t := reflect.TypeOf(x) |
|||
protoMapTypes[name] = t |
|||
revProtoTypes[t] = name |
|||
} |
|||
|
|||
// MessageName returns the fully-qualified proto name for the given message type.
|
|||
func MessageName(x Message) string { |
|||
type xname interface { |
|||
XXX_MessageName() string |
|||
} |
|||
if m, ok := x.(xname); ok { |
|||
return m.XXX_MessageName() |
|||
} |
|||
return revProtoTypes[reflect.TypeOf(x)] |
|||
} |
|||
|
|||
// MessageType returns the message type (pointer to struct) for a named message.
|
|||
// The type is not guaranteed to implement proto.Message if the name refers to a
|
|||
// map entry.
|
|||
func MessageType(name string) reflect.Type { |
|||
if t, ok := protoTypedNils[name]; ok { |
|||
return reflect.TypeOf(t) |
|||
} |
|||
return protoMapTypes[name] |
|||
} |
|||
|
|||
// A registry of all linked proto files.
|
|||
var ( |
|||
protoFiles = make(map[string][]byte) // file name => fileDescriptor
|
|||
) |
|||
|
|||
// RegisterFile is called from generated code and maps from the
|
|||
// full file name of a .proto file to its compressed FileDescriptorProto.
|
|||
func RegisterFile(filename string, fileDescriptor []byte) { |
|||
protoFiles[filename] = fileDescriptor |
|||
} |
|||
|
|||
// FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
|
|||
func FileDescriptor(filename string) []byte { return protoFiles[filename] } |
2776
vendor/github.com/golang/protobuf/proto/table_marshal.go
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,654 @@ |
|||
// Go support for Protocol Buffers - Google's data interchange format
|
|||
//
|
|||
// Copyright 2016 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 |
|||
|
|||
import ( |
|||
"fmt" |
|||
"reflect" |
|||
"strings" |
|||
"sync" |
|||
"sync/atomic" |
|||
) |
|||
|
|||
// Merge merges the src message into dst.
|
|||
// This assumes that dst and src of the same type and are non-nil.
|
|||
func (a *InternalMessageInfo) Merge(dst, src Message) { |
|||
mi := atomicLoadMergeInfo(&a.merge) |
|||
if mi == nil { |
|||
mi = getMergeInfo(reflect.TypeOf(dst).Elem()) |
|||
atomicStoreMergeInfo(&a.merge, mi) |
|||
} |
|||
mi.merge(toPointer(&dst), toPointer(&src)) |
|||
} |
|||
|
|||
type mergeInfo struct { |
|||
typ reflect.Type |
|||
|
|||
initialized int32 // 0: only typ is valid, 1: everything is valid
|
|||
lock sync.Mutex |
|||
|
|||
fields []mergeFieldInfo |
|||
unrecognized field // Offset of XXX_unrecognized
|
|||
} |
|||
|
|||
type mergeFieldInfo struct { |
|||
field field // Offset of field, guaranteed to be valid
|
|||
|
|||
// isPointer reports whether the value in the field is a pointer.
|
|||
// This is true for the following situations:
|
|||
// * Pointer to struct
|
|||
// * Pointer to basic type (proto2 only)
|
|||
// * Slice (first value in slice header is a pointer)
|
|||
// * String (first value in string header is a pointer)
|
|||
isPointer bool |
|||
|
|||
// basicWidth reports the width of the field assuming that it is directly
|
|||
// embedded in the struct (as is the case for basic types in proto3).
|
|||
// The possible values are:
|
|||
// 0: invalid
|
|||
// 1: bool
|
|||
// 4: int32, uint32, float32
|
|||
// 8: int64, uint64, float64
|
|||
basicWidth int |
|||
|
|||
// Where dst and src are pointers to the types being merged.
|
|||
merge func(dst, src pointer) |
|||
} |
|||
|
|||
var ( |
|||
mergeInfoMap = map[reflect.Type]*mergeInfo{} |
|||
mergeInfoLock sync.Mutex |
|||
) |
|||
|
|||
func getMergeInfo(t reflect.Type) *mergeInfo { |
|||
mergeInfoLock.Lock() |
|||
defer mergeInfoLock.Unlock() |
|||
mi := mergeInfoMap[t] |
|||
if mi == nil { |
|||
mi = &mergeInfo{typ: t} |
|||
mergeInfoMap[t] = mi |
|||
} |
|||
return mi |
|||
} |
|||
|
|||
// merge merges src into dst assuming they are both of type *mi.typ.
|
|||
func (mi *mergeInfo) merge(dst, src pointer) { |
|||
if dst.isNil() { |
|||
panic("proto: nil destination") |
|||
} |
|||
if src.isNil() { |
|||
return // Nothing to do.
|
|||
} |
|||
|
|||
if atomic.LoadInt32(&mi.initialized) == 0 { |
|||
mi.computeMergeInfo() |
|||
} |
|||
|
|||
for _, fi := range mi.fields { |
|||
sfp := src.offset(fi.field) |
|||
|
|||
// As an optimization, we can avoid the merge function call cost
|
|||
// if we know for sure that the source will have no effect
|
|||
// by checking if it is the zero value.
|
|||
if unsafeAllowed { |
|||
if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
|
|||
continue |
|||
} |
|||
if fi.basicWidth > 0 { |
|||
switch { |
|||
case fi.basicWidth == 1 && !*sfp.toBool(): |
|||
continue |
|||
case fi.basicWidth == 4 && *sfp.toUint32() == 0: |
|||
continue |
|||
case fi.basicWidth == 8 && *sfp.toUint64() == 0: |
|||
continue |
|||
} |
|||
} |
|||
} |
|||
|
|||
dfp := dst.offset(fi.field) |
|||
fi.merge(dfp, sfp) |
|||
} |
|||
|
|||
// TODO: Make this faster?
|
|||
out := dst.asPointerTo(mi.typ).Elem() |
|||
in := src.asPointerTo(mi.typ).Elem() |
|||
if emIn, err := extendable(in.Addr().Interface()); err == nil { |
|||
emOut, _ := extendable(out.Addr().Interface()) |
|||
mIn, muIn := emIn.extensionsRead() |
|||
if mIn != nil { |
|||
mOut := emOut.extensionsWrite() |
|||
muIn.Lock() |
|||
mergeExtension(mOut, mIn) |
|||
muIn.Unlock() |
|||
} |
|||
} |
|||
|
|||
if mi.unrecognized.IsValid() { |
|||
if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { |
|||
*dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) |
|||
} |
|||
} |
|||
} |
|||
|
|||
func (mi *mergeInfo) computeMergeInfo() { |
|||
mi.lock.Lock() |
|||
defer mi.lock.Unlock() |
|||
if mi.initialized != 0 { |
|||
return |
|||
} |
|||
t := mi.typ |
|||
n := t.NumField() |
|||
|
|||
props := GetProperties(t) |
|||
for i := 0; i < n; i++ { |
|||
f := t.Field(i) |
|||
if strings.HasPrefix(f.Name, "XXX_") { |
|||
continue |
|||
} |
|||
|
|||
mfi := mergeFieldInfo{field: toField(&f)} |
|||
tf := f.Type |
|||
|
|||
// As an optimization, we can avoid the merge function call cost
|
|||
// if we know for sure that the source will have no effect
|
|||
// by checking if it is the zero value.
|
|||
if unsafeAllowed { |
|||
switch tf.Kind() { |
|||
case reflect.Ptr, reflect.Slice, reflect.String: |
|||
// As a special case, we assume slices and strings are pointers
|
|||
// since we know that the first field in the SliceSlice or
|
|||
// StringHeader is a data pointer.
|
|||
mfi.isPointer = true |
|||
case reflect.Bool: |
|||
mfi.basicWidth = 1 |
|||
case reflect.Int32, reflect.Uint32, reflect.Float32: |
|||
mfi.basicWidth = 4 |
|||
case reflect.Int64, reflect.Uint64, reflect.Float64: |
|||
mfi.basicWidth = 8 |
|||
} |
|||
} |
|||
|
|||
// Unwrap tf to get at its most basic type.
|
|||
var isPointer, isSlice bool |
|||
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { |
|||
isSlice = true |
|||
tf = tf.Elem() |
|||
} |
|||
if tf.Kind() == reflect.Ptr { |
|||
isPointer = true |
|||
tf = tf.Elem() |
|||
} |
|||
if isPointer && isSlice && tf.Kind() != reflect.Struct { |
|||
panic("both pointer and slice for basic type in " + tf.Name()) |
|||
} |
|||
|
|||
switch tf.Kind() { |
|||
case reflect.Int32: |
|||
switch { |
|||
case isSlice: // E.g., []int32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
// NOTE: toInt32Slice is not defined (see pointer_reflect.go).
|
|||
/* |
|||
sfsp := src.toInt32Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toInt32Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []int64{} |
|||
} |
|||
} |
|||
*/ |
|||
sfs := src.getInt32Slice() |
|||
if sfs != nil { |
|||
dfs := dst.getInt32Slice() |
|||
dfs = append(dfs, sfs...) |
|||
if dfs == nil { |
|||
dfs = []int32{} |
|||
} |
|||
dst.setInt32Slice(dfs) |
|||
} |
|||
} |
|||
case isPointer: // E.g., *int32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
// NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
|
|||
/* |
|||
sfpp := src.toInt32Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toInt32Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Int32(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
*/ |
|||
sfp := src.getInt32Ptr() |
|||
if sfp != nil { |
|||
dfp := dst.getInt32Ptr() |
|||
if dfp == nil { |
|||
dst.setInt32Ptr(*sfp) |
|||
} else { |
|||
*dfp = *sfp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., int32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toInt32(); v != 0 { |
|||
*dst.toInt32() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Int64: |
|||
switch { |
|||
case isSlice: // E.g., []int64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toInt64Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toInt64Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []int64{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *int64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toInt64Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toInt64Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Int64(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., int64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toInt64(); v != 0 { |
|||
*dst.toInt64() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Uint32: |
|||
switch { |
|||
case isSlice: // E.g., []uint32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toUint32Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toUint32Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []uint32{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *uint32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toUint32Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toUint32Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Uint32(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., uint32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toUint32(); v != 0 { |
|||
*dst.toUint32() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Uint64: |
|||
switch { |
|||
case isSlice: // E.g., []uint64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toUint64Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toUint64Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []uint64{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *uint64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toUint64Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toUint64Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Uint64(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., uint64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toUint64(); v != 0 { |
|||
*dst.toUint64() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Float32: |
|||
switch { |
|||
case isSlice: // E.g., []float32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toFloat32Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toFloat32Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []float32{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *float32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toFloat32Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toFloat32Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Float32(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., float32
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toFloat32(); v != 0 { |
|||
*dst.toFloat32() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Float64: |
|||
switch { |
|||
case isSlice: // E.g., []float64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toFloat64Slice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toFloat64Slice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []float64{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *float64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toFloat64Ptr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toFloat64Ptr() |
|||
if *dfpp == nil { |
|||
*dfpp = Float64(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., float64
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toFloat64(); v != 0 { |
|||
*dst.toFloat64() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Bool: |
|||
switch { |
|||
case isSlice: // E.g., []bool
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toBoolSlice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toBoolSlice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []bool{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *bool
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toBoolPtr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toBoolPtr() |
|||
if *dfpp == nil { |
|||
*dfpp = Bool(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., bool
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toBool(); v { |
|||
*dst.toBool() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.String: |
|||
switch { |
|||
case isSlice: // E.g., []string
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfsp := src.toStringSlice() |
|||
if *sfsp != nil { |
|||
dfsp := dst.toStringSlice() |
|||
*dfsp = append(*dfsp, *sfsp...) |
|||
if *dfsp == nil { |
|||
*dfsp = []string{} |
|||
} |
|||
} |
|||
} |
|||
case isPointer: // E.g., *string
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sfpp := src.toStringPtr() |
|||
if *sfpp != nil { |
|||
dfpp := dst.toStringPtr() |
|||
if *dfpp == nil { |
|||
*dfpp = String(**sfpp) |
|||
} else { |
|||
**dfpp = **sfpp |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., string
|
|||
mfi.merge = func(dst, src pointer) { |
|||
if v := *src.toString(); v != "" { |
|||
*dst.toString() = v |
|||
} |
|||
} |
|||
} |
|||
case reflect.Slice: |
|||
isProto3 := props.Prop[i].proto3 |
|||
switch { |
|||
case isPointer: |
|||
panic("bad pointer in byte slice case in " + tf.Name()) |
|||
case tf.Elem().Kind() != reflect.Uint8: |
|||
panic("bad element kind in byte slice case in " + tf.Name()) |
|||
case isSlice: // E.g., [][]byte
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sbsp := src.toBytesSlice() |
|||
if *sbsp != nil { |
|||
dbsp := dst.toBytesSlice() |
|||
for _, sb := range *sbsp { |
|||
if sb == nil { |
|||
*dbsp = append(*dbsp, nil) |
|||
} else { |
|||
*dbsp = append(*dbsp, append([]byte{}, sb...)) |
|||
} |
|||
} |
|||
if *dbsp == nil { |
|||
*dbsp = [][]byte{} |
|||
} |
|||
} |
|||
} |
|||
default: // E.g., []byte
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sbp := src.toBytes() |
|||
if *sbp != nil { |
|||
dbp := dst.toBytes() |
|||
if !isProto3 || len(*sbp) > 0 { |
|||
*dbp = append([]byte{}, *sbp...) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
case reflect.Struct: |
|||
switch { |
|||
case !isPointer: |
|||
panic(fmt.Sprintf("message field %s without pointer", tf)) |
|||
case isSlice: // E.g., []*pb.T
|
|||
mi := getMergeInfo(tf) |
|||
mfi.merge = func(dst, src pointer) { |
|||
sps := src.getPointerSlice() |
|||
if sps != nil { |
|||
dps := dst.getPointerSlice() |
|||
for _, sp := range sps { |
|||
var dp pointer |
|||
if !sp.isNil() { |
|||
dp = valToPointer(reflect.New(tf)) |
|||
mi.merge(dp, sp) |
|||
} |
|||
dps = append(dps, dp) |
|||
} |
|||
if dps == nil { |
|||
dps = []pointer{} |
|||
} |
|||
dst.setPointerSlice(dps) |
|||
} |
|||
} |
|||
default: // E.g., *pb.T
|
|||
mi := getMergeInfo(tf) |
|||
mfi.merge = func(dst, src pointer) { |
|||
sp := src.getPointer() |
|||
if !sp.isNil() { |
|||
dp := dst.getPointer() |
|||
if dp.isNil() { |
|||
dp = valToPointer(reflect.New(tf)) |
|||
dst.setPointer(dp) |
|||
} |
|||
mi.merge(dp, sp) |
|||
} |
|||
} |
|||
} |
|||
case reflect.Map: |
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic("bad pointer or slice in map case in " + tf.Name()) |
|||
default: // E.g., map[K]V
|
|||
mfi.merge = func(dst, src pointer) { |
|||
sm := src.asPointerTo(tf).Elem() |
|||
if sm.Len() == 0 { |
|||
return |
|||
} |
|||
dm := dst.asPointerTo(tf).Elem() |
|||
if dm.IsNil() { |
|||
dm.Set(reflect.MakeMap(tf)) |
|||
} |
|||
|
|||
switch tf.Elem().Kind() { |
|||
case reflect.Ptr: // Proto struct (e.g., *T)
|
|||
for _, key := range sm.MapKeys() { |
|||
val := sm.MapIndex(key) |
|||
val = reflect.ValueOf(Clone(val.Interface().(Message))) |
|||
dm.SetMapIndex(key, val) |
|||
} |
|||
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
|
|||
for _, key := range sm.MapKeys() { |
|||
val := sm.MapIndex(key) |
|||
val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) |
|||
dm.SetMapIndex(key, val) |
|||
} |
|||
default: // Basic type (e.g., string)
|
|||
for _, key := range sm.MapKeys() { |
|||
val := sm.MapIndex(key) |
|||
dm.SetMapIndex(key, val) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
case reflect.Interface: |
|||
// Must be oneof field.
|
|||
switch { |
|||
case isPointer || isSlice: |
|||
panic("bad pointer or slice in interface case in " + tf.Name()) |
|||
default: // E.g., interface{}
|
|||
// TODO: Make this faster?
|
|||
mfi.merge = func(dst, src pointer) { |
|||
su := src.asPointerTo(tf).Elem() |
|||
if !su.IsNil() { |
|||
du := dst.asPointerTo(tf).Elem() |
|||
typ := su.Elem().Type() |
|||
if du.IsNil() || du.Elem().Type() != typ { |
|||
du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
|
|||
} |
|||
sv := su.Elem().Elem().Field(0) |
|||
if sv.Kind() == reflect.Ptr && sv.IsNil() { |
|||
return |
|||
} |
|||
dv := du.Elem().Elem().Field(0) |
|||
if dv.Kind() == reflect.Ptr && dv.IsNil() { |
|||
dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
|
|||
} |
|||
switch sv.Type().Kind() { |
|||
case reflect.Ptr: // Proto struct (e.g., *T)
|
|||
Merge(dv.Interface().(Message), sv.Interface().(Message)) |
|||
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
|
|||
dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) |
|||
default: // Basic type (e.g., string)
|
|||
dv.Set(sv) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
default: |
|||
panic(fmt.Sprintf("merger not found for type:%s", tf)) |
|||
} |
|||
mi.fields = append(mi.fields, mfi) |
|||
} |
|||
|
|||
mi.unrecognized = invalidField |
|||
if f, ok := t.FieldByName("XXX_unrecognized"); ok { |
|||
if f.Type != reflect.TypeOf([]byte{}) { |
|||
panic("expected XXX_unrecognized to be of type []byte") |
|||
} |
|||
mi.unrecognized = toField(&f) |
|||
} |
|||
|
|||
atomic.StoreInt32(&mi.initialized, 1) |
|||
} |
2053
vendor/github.com/golang/protobuf/proto/table_unmarshal.go
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,845 @@ |
|||
// 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 |
|||
|
|||
// Functions for writing the text protocol buffer format.
|
|||
|
|||
import ( |
|||
"bufio" |
|||
"bytes" |
|||
"encoding" |
|||
"errors" |
|||
"fmt" |
|||
"io" |
|||
"log" |
|||
"math" |
|||
"reflect" |
|||
"sort" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
newline = []byte("\n") |
|||
spaces = []byte(" ") |
|||
endBraceNewline = []byte("}\n") |
|||
backslashN = []byte{'\\', 'n'} |
|||
backslashR = []byte{'\\', 'r'} |
|||
backslashT = []byte{'\\', 't'} |
|||
backslashDQ = []byte{'\\', '"'} |
|||
backslashBS = []byte{'\\', '\\'} |
|||
posInf = []byte("inf") |
|||
negInf = []byte("-inf") |
|||
nan = []byte("nan") |
|||
) |
|||
|
|||
type writer interface { |
|||
io.Writer |
|||
WriteByte(byte) error |
|||
} |
|||
|
|||
// textWriter is an io.Writer that tracks its indentation level.
|
|||
type textWriter struct { |
|||
ind int |
|||
complete bool // if the current position is a complete line
|
|||
compact bool // whether to write out as a one-liner
|
|||
w writer |
|||
} |
|||
|
|||
func (w *textWriter) WriteString(s string) (n int, err error) { |
|||
if !strings.Contains(s, "\n") { |
|||
if !w.compact && w.complete { |
|||
w.writeIndent() |
|||
} |
|||
w.complete = false |
|||
return io.WriteString(w.w, s) |
|||
} |
|||
// WriteString is typically called without newlines, so this
|
|||
// codepath and its copy are rare. We copy to avoid
|
|||
// duplicating all of Write's logic here.
|
|||
return w.Write([]byte(s)) |
|||
} |
|||
|
|||
func (w *textWriter) Write(p []byte) (n int, err error) { |
|||
newlines := bytes.Count(p, newline) |
|||
if newlines == 0 { |
|||
if !w.compact && w.complete { |
|||
w.writeIndent() |
|||
} |
|||
n, err = w.w.Write(p) |
|||
w.complete = false |
|||
return n, err |
|||
} |
|||
|
|||
frags := bytes.SplitN(p, newline, newlines+1) |
|||
if w.compact { |
|||
for i, frag := range frags { |
|||
if i > 0 { |
|||
if err := w.w.WriteByte(' '); err != nil { |
|||
return n, err |
|||
} |
|||
n++ |
|||
} |
|||
nn, err := w.w.Write(frag) |
|||
n += nn |
|||
if err != nil { |
|||
return n, err |
|||
} |
|||
} |
|||
return n, nil |
|||
} |
|||
|
|||
for i, frag := range frags { |
|||
if w.complete { |
|||
w.writeIndent() |
|||
} |
|||
nn, err := w.w.Write(frag) |
|||
n += nn |
|||
if err != nil { |
|||
return n, err |
|||
} |
|||
if i+1 < len(frags) { |
|||
if err := w.w.WriteByte('\n'); err != nil { |
|||
return n, err |
|||
} |
|||
n++ |
|||
} |
|||
} |
|||
w.complete = len(frags[len(frags)-1]) == 0 |
|||
return n, nil |
|||
} |
|||
|
|||
func (w *textWriter) WriteByte(c byte) error { |
|||
if w.compact && c == '\n' { |
|||
c = ' ' |
|||
} |
|||
if !w.compact && w.complete { |
|||
w.writeIndent() |
|||
} |
|||
err := w.w.WriteByte(c) |
|||
w.complete = c == '\n' |
|||
return err |
|||
} |
|||
|
|||
func (w *textWriter) indent() { w.ind++ } |
|||
|
|||
func (w *textWriter) unindent() { |
|||
if w.ind == 0 { |
|||
log.Print("proto: textWriter unindented too far") |
|||
return |
|||
} |
|||
w.ind-- |
|||
} |
|||
|
|||
func writeName(w *textWriter, props *Properties) error { |
|||
if _, err := w.WriteString(props.OrigName); err != nil { |
|||
return err |
|||
} |
|||
if props.Wire != "group" { |
|||
return w.WriteByte(':') |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func requiresQuotes(u string) bool { |
|||
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
|||
for _, ch := range u { |
|||
switch { |
|||
case ch == '.' || ch == '/' || ch == '_': |
|||
continue |
|||
case '0' <= ch && ch <= '9': |
|||
continue |
|||
case 'A' <= ch && ch <= 'Z': |
|||
continue |
|||
case 'a' <= ch && ch <= 'z': |
|||
continue |
|||
default: |
|||
return true |
|||
} |
|||
} |
|||
return false |
|||
} |
|||
|
|||
// isAny reports whether sv is a google.protobuf.Any message
|
|||
func isAny(sv reflect.Value) bool { |
|||
type wkt interface { |
|||
XXX_WellKnownType() string |
|||
} |
|||
t, ok := sv.Addr().Interface().(wkt) |
|||
return ok && t.XXX_WellKnownType() == "Any" |
|||
} |
|||
|
|||
// writeProto3Any writes an expanded google.protobuf.Any message.
|
|||
//
|
|||
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
|||
// required messages are not linked in).
|
|||
//
|
|||
// It returns (true, error) when sv was written in expanded format or an error
|
|||
// was encountered.
|
|||
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { |
|||
turl := sv.FieldByName("TypeUrl") |
|||
val := sv.FieldByName("Value") |
|||
if !turl.IsValid() || !val.IsValid() { |
|||
return true, errors.New("proto: invalid google.protobuf.Any message") |
|||
} |
|||
|
|||
b, ok := val.Interface().([]byte) |
|||
if !ok { |
|||
return true, errors.New("proto: invalid google.protobuf.Any message") |
|||
} |
|||
|
|||
parts := strings.Split(turl.String(), "/") |
|||
mt := MessageType(parts[len(parts)-1]) |
|||
if mt == nil { |
|||
return false, nil |
|||
} |
|||
m := reflect.New(mt.Elem()) |
|||
if err := Unmarshal(b, m.Interface().(Message)); err != nil { |
|||
return false, nil |
|||
} |
|||
w.Write([]byte("[")) |
|||
u := turl.String() |
|||
if requiresQuotes(u) { |
|||
writeString(w, u) |
|||
} else { |
|||
w.Write([]byte(u)) |
|||
} |
|||
if w.compact { |
|||
w.Write([]byte("]:<")) |
|||
} else { |
|||
w.Write([]byte("]: <\n")) |
|||
w.ind++ |
|||
} |
|||
if err := tm.writeStruct(w, m.Elem()); err != nil { |
|||
return true, err |
|||
} |
|||
if w.compact { |
|||
w.Write([]byte("> ")) |
|||
} else { |
|||
w.ind-- |
|||
w.Write([]byte(">\n")) |
|||
} |
|||
return true, nil |
|||
} |
|||
|
|||
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { |
|||
if tm.ExpandAny && isAny(sv) { |
|||
if canExpand, err := tm.writeProto3Any(w, sv); canExpand { |
|||
return err |
|||
} |
|||
} |
|||
st := sv.Type() |
|||
sprops := GetProperties(st) |
|||
for i := 0; i < sv.NumField(); i++ { |
|||
fv := sv.Field(i) |
|||
props := sprops.Prop[i] |
|||
name := st.Field(i).Name |
|||
|
|||
if name == "XXX_NoUnkeyedLiteral" { |
|||
continue |
|||
} |
|||
|
|||
if strings.HasPrefix(name, "XXX_") { |
|||
// There are two XXX_ fields:
|
|||
// XXX_unrecognized []byte
|
|||
// XXX_extensions map[int32]proto.Extension
|
|||
// The first is handled here;
|
|||
// the second is handled at the bottom of this function.
|
|||
if name == "XXX_unrecognized" && !fv.IsNil() { |
|||
if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
continue |
|||
} |
|||
if fv.Kind() == reflect.Ptr && fv.IsNil() { |
|||
// Field not filled in. This could be an optional field or
|
|||
// a required field that wasn't filled in. Either way, there
|
|||
// isn't anything we can show for it.
|
|||
continue |
|||
} |
|||
if fv.Kind() == reflect.Slice && fv.IsNil() { |
|||
// Repeated field that is empty, or a bytes field that is unused.
|
|||
continue |
|||
} |
|||
|
|||
if props.Repeated && fv.Kind() == reflect.Slice { |
|||
// Repeated field.
|
|||
for j := 0; j < fv.Len(); j++ { |
|||
if err := writeName(w, props); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
v := fv.Index(j) |
|||
if v.Kind() == reflect.Ptr && v.IsNil() { |
|||
// A nil message in a repeated field is not valid,
|
|||
// but we can handle that more gracefully than panicking.
|
|||
if _, err := w.Write([]byte("<nil>\n")); err != nil { |
|||
return err |
|||
} |
|||
continue |
|||
} |
|||
if err := tm.writeAny(w, v, props); err != nil { |
|||
return err |
|||
} |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
continue |
|||
} |
|||
if fv.Kind() == reflect.Map { |
|||
// Map fields are rendered as a repeated struct with key/value fields.
|
|||
keys := fv.MapKeys() |
|||
sort.Sort(mapKeys(keys)) |
|||
for _, key := range keys { |
|||
val := fv.MapIndex(key) |
|||
if err := writeName(w, props); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
// open struct
|
|||
if err := w.WriteByte('<'); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
w.indent() |
|||
// key
|
|||
if _, err := w.WriteString("key:"); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { |
|||
return err |
|||
} |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
// nil values aren't legal, but we can avoid panicking because of them.
|
|||
if val.Kind() != reflect.Ptr || !val.IsNil() { |
|||
// value
|
|||
if _, err := w.WriteString("value:"); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
if err := tm.writeAny(w, val, props.MapValProp); err != nil { |
|||
return err |
|||
} |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
// close struct
|
|||
w.unindent() |
|||
if err := w.WriteByte('>'); err != nil { |
|||
return err |
|||
} |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
continue |
|||
} |
|||
if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { |
|||
// empty bytes field
|
|||
continue |
|||
} |
|||
if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { |
|||
// proto3 non-repeated scalar field; skip if zero value
|
|||
if isProto3Zero(fv) { |
|||
continue |
|||
} |
|||
} |
|||
|
|||
if fv.Kind() == reflect.Interface { |
|||
// Check if it is a oneof.
|
|||
if st.Field(i).Tag.Get("protobuf_oneof") != "" { |
|||
// fv is nil, or holds a pointer to generated struct.
|
|||
// That generated struct has exactly one field,
|
|||
// which has a protobuf struct tag.
|
|||
if fv.IsNil() { |
|||
continue |
|||
} |
|||
inner := fv.Elem().Elem() // interface -> *T -> T
|
|||
tag := inner.Type().Field(0).Tag.Get("protobuf") |
|||
props = new(Properties) // Overwrite the outer props var, but not its pointee.
|
|||
props.Parse(tag) |
|||
// Write the value in the oneof, not the oneof itself.
|
|||
fv = inner.Field(0) |
|||
|
|||
// Special case to cope with malformed messages gracefully:
|
|||
// If the value in the oneof is a nil pointer, don't panic
|
|||
// in writeAny.
|
|||
if fv.Kind() == reflect.Ptr && fv.IsNil() { |
|||
// Use errors.New so writeAny won't render quotes.
|
|||
msg := errors.New("/* nil */") |
|||
fv = reflect.ValueOf(&msg).Elem() |
|||
} |
|||
} |
|||
} |
|||
|
|||
if err := writeName(w, props); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
|
|||
// Enums have a String method, so writeAny will work fine.
|
|||
if err := tm.writeAny(w, fv, props); err != nil { |
|||
return err |
|||
} |
|||
|
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
|
|||
// Extensions (the XXX_extensions field).
|
|||
pv := sv.Addr() |
|||
if _, err := extendable(pv.Interface()); err == nil { |
|||
if err := tm.writeExtensions(w, pv); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() |
|||
|
|||
// writeAny writes an arbitrary field.
|
|||
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { |
|||
v = reflect.Indirect(v) |
|||
|
|||
// Floats have special cases.
|
|||
if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { |
|||
x := v.Float() |
|||
var b []byte |
|||
switch { |
|||
case math.IsInf(x, 1): |
|||
b = posInf |
|||
case math.IsInf(x, -1): |
|||
b = negInf |
|||
case math.IsNaN(x): |
|||
b = nan |
|||
} |
|||
if b != nil { |
|||
_, err := w.Write(b) |
|||
return err |
|||
} |
|||
// Other values are handled below.
|
|||
} |
|||
|
|||
// We don't attempt to serialise every possible value type; only those
|
|||
// that can occur in protocol buffers.
|
|||
switch v.Kind() { |
|||
case reflect.Slice: |
|||
// Should only be a []byte; repeated fields are handled in writeStruct.
|
|||
if err := writeString(w, string(v.Bytes())); err != nil { |
|||
return err |
|||
} |
|||
case reflect.String: |
|||
if err := writeString(w, v.String()); err != nil { |
|||
return err |
|||
} |
|||
case reflect.Struct: |
|||
// Required/optional group/message.
|
|||
var bra, ket byte = '<', '>' |
|||
if props != nil && props.Wire == "group" { |
|||
bra, ket = '{', '}' |
|||
} |
|||
if err := w.WriteByte(bra); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
w.indent() |
|||
if v.CanAddr() { |
|||
// Calling v.Interface on a struct causes the reflect package to
|
|||
// copy the entire struct. This is racy with the new Marshaler
|
|||
// since we atomically update the XXX_sizecache.
|
|||
//
|
|||
// Thus, we retrieve a pointer to the struct if possible to avoid
|
|||
// a race since v.Interface on the pointer doesn't copy the struct.
|
|||
//
|
|||
// If v is not addressable, then we are not worried about a race
|
|||
// since it implies that the binary Marshaler cannot possibly be
|
|||
// mutating this value.
|
|||
v = v.Addr() |
|||
} |
|||
if v.Type().Implements(textMarshalerType) { |
|||
text, err := v.Interface().(encoding.TextMarshaler).MarshalText() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if _, err = w.Write(text); err != nil { |
|||
return err |
|||
} |
|||
} else { |
|||
if v.Kind() == reflect.Ptr { |
|||
v = v.Elem() |
|||
} |
|||
if err := tm.writeStruct(w, v); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
w.unindent() |
|||
if err := w.WriteByte(ket); err != nil { |
|||
return err |
|||
} |
|||
default: |
|||
_, err := fmt.Fprint(w, v.Interface()) |
|||
return err |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// equivalent to C's isprint.
|
|||
func isprint(c byte) bool { |
|||
return c >= 0x20 && c < 0x7f |
|||
} |
|||
|
|||
// writeString writes a string in the protocol buffer text format.
|
|||
// It is similar to strconv.Quote except we don't use Go escape sequences,
|
|||
// we treat the string as a byte sequence, and we use octal escapes.
|
|||
// These differences are to maintain interoperability with the other
|
|||
// languages' implementations of the text format.
|
|||
func writeString(w *textWriter, s string) error { |
|||
// use WriteByte here to get any needed indent
|
|||
if err := w.WriteByte('"'); err != nil { |
|||
return err |
|||
} |
|||
// Loop over the bytes, not the runes.
|
|||
for i := 0; i < len(s); i++ { |
|||
var err error |
|||
// Divergence from C++: we don't escape apostrophes.
|
|||
// There's no need to escape them, and the C++ parser
|
|||
// copes with a naked apostrophe.
|
|||
switch c := s[i]; c { |
|||
case '\n': |
|||
_, err = w.w.Write(backslashN) |
|||
case '\r': |
|||
_, err = w.w.Write(backslashR) |
|||
case '\t': |
|||
_, err = w.w.Write(backslashT) |
|||
case '"': |
|||
_, err = w.w.Write(backslashDQ) |
|||
case '\\': |
|||
_, err = w.w.Write(backslashBS) |
|||
default: |
|||
if isprint(c) { |
|||
err = w.w.WriteByte(c) |
|||
} else { |
|||
_, err = fmt.Fprintf(w.w, "\\%03o", c) |
|||
} |
|||
} |
|||
if err != nil { |
|||
return err |
|||
} |
|||
} |
|||
return w.WriteByte('"') |
|||
} |
|||
|
|||
func writeUnknownStruct(w *textWriter, data []byte) (err error) { |
|||
if !w.compact { |
|||
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
b := NewBuffer(data) |
|||
for b.index < len(b.buf) { |
|||
x, err := b.DecodeVarint() |
|||
if err != nil { |
|||
_, err := fmt.Fprintf(w, "/* %v */\n", err) |
|||
return err |
|||
} |
|||
wire, tag := x&7, x>>3 |
|||
if wire == WireEndGroup { |
|||
w.unindent() |
|||
if _, err := w.Write(endBraceNewline); err != nil { |
|||
return err |
|||
} |
|||
continue |
|||
} |
|||
if _, err := fmt.Fprint(w, tag); err != nil { |
|||
return err |
|||
} |
|||
if wire != WireStartGroup { |
|||
if err := w.WriteByte(':'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
if !w.compact || wire == WireStartGroup { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
switch wire { |
|||
case WireBytes: |
|||
buf, e := b.DecodeRawBytes(false) |
|||
if e == nil { |
|||
_, err = fmt.Fprintf(w, "%q", buf) |
|||
} else { |
|||
_, err = fmt.Fprintf(w, "/* %v */", e) |
|||
} |
|||
case WireFixed32: |
|||
x, err = b.DecodeFixed32() |
|||
err = writeUnknownInt(w, x, err) |
|||
case WireFixed64: |
|||
x, err = b.DecodeFixed64() |
|||
err = writeUnknownInt(w, x, err) |
|||
case WireStartGroup: |
|||
err = w.WriteByte('{') |
|||
w.indent() |
|||
case WireVarint: |
|||
x, err = b.DecodeVarint() |
|||
err = writeUnknownInt(w, x, err) |
|||
default: |
|||
_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) |
|||
} |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if err = w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func writeUnknownInt(w *textWriter, x uint64, err error) error { |
|||
if err == nil { |
|||
_, err = fmt.Fprint(w, x) |
|||
} else { |
|||
_, err = fmt.Fprintf(w, "/* %v */", err) |
|||
} |
|||
return err |
|||
} |
|||
|
|||
type int32Slice []int32 |
|||
|
|||
func (s int32Slice) Len() int { return len(s) } |
|||
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } |
|||
func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
|||
|
|||
// writeExtensions writes all the extensions in pv.
|
|||
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
|||
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { |
|||
emap := extensionMaps[pv.Type().Elem()] |
|||
ep, _ := extendable(pv.Interface()) |
|||
|
|||
// Order the extensions by ID.
|
|||
// This isn't strictly necessary, but it will give us
|
|||
// canonical output, which will also make testing easier.
|
|||
m, mu := ep.extensionsRead() |
|||
if m == nil { |
|||
return nil |
|||
} |
|||
mu.Lock() |
|||
ids := make([]int32, 0, len(m)) |
|||
for id := range m { |
|||
ids = append(ids, id) |
|||
} |
|||
sort.Sort(int32Slice(ids)) |
|||
mu.Unlock() |
|||
|
|||
for _, extNum := range ids { |
|||
ext := m[extNum] |
|||
var desc *ExtensionDesc |
|||
if emap != nil { |
|||
desc = emap[extNum] |
|||
} |
|||
if desc == nil { |
|||
// Unknown extension.
|
|||
if err := writeUnknownStruct(w, ext.enc); err != nil { |
|||
return err |
|||
} |
|||
continue |
|||
} |
|||
|
|||
pb, err := GetExtension(ep, desc) |
|||
if err != nil { |
|||
return fmt.Errorf("failed getting extension: %v", err) |
|||
} |
|||
|
|||
// Repeated extensions will appear as a slice.
|
|||
if !desc.repeated() { |
|||
if err := tm.writeExtension(w, desc.Name, pb); err != nil { |
|||
return err |
|||
} |
|||
} else { |
|||
v := reflect.ValueOf(pb) |
|||
for i := 0; i < v.Len(); i++ { |
|||
if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { |
|||
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { |
|||
return err |
|||
} |
|||
if !w.compact { |
|||
if err := w.WriteByte(' '); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { |
|||
return err |
|||
} |
|||
if err := w.WriteByte('\n'); err != nil { |
|||
return err |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (w *textWriter) writeIndent() { |
|||
if !w.complete { |
|||
return |
|||
} |
|||
remain := w.ind * 2 |
|||
for remain > 0 { |
|||
n := remain |
|||
if n > len(spaces) { |
|||
n = len(spaces) |
|||
} |
|||
w.w.Write(spaces[:n]) |
|||
remain -= n |
|||
} |
|||
w.complete = false |
|||
} |
|||
|
|||
// TextMarshaler is a configurable text format marshaler.
|
|||
type TextMarshaler struct { |
|||
Compact bool // use compact text format (one line).
|
|||
ExpandAny bool // expand google.protobuf.Any messages of known types
|
|||
} |
|||
|
|||
// Marshal writes a given protocol buffer in text format.
|
|||
// The only errors returned are from w.
|
|||
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { |
|||
val := reflect.ValueOf(pb) |
|||
if pb == nil || val.IsNil() { |
|||
w.Write([]byte("<nil>")) |
|||
return nil |
|||
} |
|||
var bw *bufio.Writer |
|||
ww, ok := w.(writer) |
|||
if !ok { |
|||
bw = bufio.NewWriter(w) |
|||
ww = bw |
|||
} |
|||
aw := &textWriter{ |
|||
w: ww, |
|||
complete: true, |
|||
compact: tm.Compact, |
|||
} |
|||
|
|||
if etm, ok := pb.(encoding.TextMarshaler); ok { |
|||
text, err := etm.MarshalText() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if _, err = aw.Write(text); err != nil { |
|||
return err |
|||
} |
|||
if bw != nil { |
|||
return bw.Flush() |
|||
} |
|||
return nil |
|||
} |
|||
// Dereference the received pointer so we don't have outer < and >.
|
|||
v := reflect.Indirect(val) |
|||
if err := tm.writeStruct(aw, v); err != nil { |
|||
return err |
|||
} |
|||
if bw != nil { |
|||
return bw.Flush() |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// Text is the same as Marshal, but returns the string directly.
|
|||
func (tm *TextMarshaler) Text(pb Message) string { |
|||
var buf bytes.Buffer |
|||
tm.Marshal(&buf, pb) |
|||
return buf.String() |
|||
} |
|||
|
|||
var ( |
|||
defaultTextMarshaler = TextMarshaler{} |
|||
compactTextMarshaler = TextMarshaler{Compact: true} |
|||
) |
|||
|
|||
// TODO: consider removing some of the Marshal functions below.
|
|||
|
|||
// MarshalText writes a given protocol buffer in text format.
|
|||
// The only errors returned are from w.
|
|||
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } |
|||
|
|||
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
|||
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } |
|||
|
|||
// CompactText writes a given protocol buffer in compact text format (one line).
|
|||
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } |
|||
|
|||
// CompactTextString is the same as CompactText, but returns the string directly.
|
|||
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } |
@ -0,0 +1,880 @@ |
|||
// 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 |
|||
|
|||
// Functions for parsing the Text protocol buffer format.
|
|||
// TODO: message sets.
|
|||
|
|||
import ( |
|||
"encoding" |
|||
"errors" |
|||
"fmt" |
|||
"reflect" |
|||
"strconv" |
|||
"strings" |
|||
"unicode/utf8" |
|||
) |
|||
|
|||
// Error string emitted when deserializing Any and fields are already set
|
|||
const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" |
|||
|
|||
type ParseError struct { |
|||
Message string |
|||
Line int // 1-based line number
|
|||
Offset int // 0-based byte offset from start of input
|
|||
} |
|||
|
|||
func (p *ParseError) Error() string { |
|||
if p.Line == 1 { |
|||
// show offset only for first line
|
|||
return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) |
|||
} |
|||
return fmt.Sprintf("line %d: %v", p.Line, p.Message) |
|||
} |
|||
|
|||
type token struct { |
|||
value string |
|||
err *ParseError |
|||
line int // line number
|
|||
offset int // byte number from start of input, not start of line
|
|||
unquoted string // the unquoted version of value, if it was a quoted string
|
|||
} |
|||
|
|||
func (t *token) String() string { |
|||
if t.err == nil { |
|||
return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) |
|||
} |
|||
return fmt.Sprintf("parse error: %v", t.err) |
|||
} |
|||
|
|||
type textParser struct { |
|||
s string // remaining input
|
|||
done bool // whether the parsing is finished (success or error)
|
|||
backed bool // whether back() was called
|
|||
offset, line int |
|||
cur token |
|||
} |
|||
|
|||
func newTextParser(s string) *textParser { |
|||
p := new(textParser) |
|||
p.s = s |
|||
p.line = 1 |
|||
p.cur.line = 1 |
|||
return p |
|||
} |
|||
|
|||
func (p *textParser) errorf(format string, a ...interface{}) *ParseError { |
|||
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} |
|||
p.cur.err = pe |
|||
p.done = true |
|||
return pe |
|||
} |
|||
|
|||
// Numbers and identifiers are matched by [-+._A-Za-z0-9]
|
|||
func isIdentOrNumberChar(c byte) bool { |
|||
switch { |
|||
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': |
|||
return true |
|||
case '0' <= c && c <= '9': |
|||
return true |
|||
} |
|||
switch c { |
|||
case '-', '+', '.', '_': |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
func isWhitespace(c byte) bool { |
|||
switch c { |
|||
case ' ', '\t', '\n', '\r': |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
func isQuote(c byte) bool { |
|||
switch c { |
|||
case '"', '\'': |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
func (p *textParser) skipWhitespace() { |
|||
i := 0 |
|||
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { |
|||
if p.s[i] == '#' { |
|||
// comment; skip to end of line or input
|
|||
for i < len(p.s) && p.s[i] != '\n' { |
|||
i++ |
|||
} |
|||
if i == len(p.s) { |
|||
break |
|||
} |
|||
} |
|||
if p.s[i] == '\n' { |
|||
p.line++ |
|||
} |
|||
i++ |
|||
} |
|||
p.offset += i |
|||
p.s = p.s[i:len(p.s)] |
|||
if len(p.s) == 0 { |
|||
p.done = true |
|||
} |
|||
} |
|||
|
|||
func (p *textParser) advance() { |
|||
// Skip whitespace
|
|||
p.skipWhitespace() |
|||
if p.done { |
|||
return |
|||
} |
|||
|
|||
// Start of non-whitespace
|
|||
p.cur.err = nil |
|||
p.cur.offset, p.cur.line = p.offset, p.line |
|||
p.cur.unquoted = "" |
|||
switch p.s[0] { |
|||
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': |
|||
// Single symbol
|
|||
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] |
|||
case '"', '\'': |
|||
// Quoted string
|
|||
i := 1 |
|||
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { |
|||
if p.s[i] == '\\' && i+1 < len(p.s) { |
|||
// skip escaped char
|
|||
i++ |
|||
} |
|||
i++ |
|||
} |
|||
if i >= len(p.s) || p.s[i] != p.s[0] { |
|||
p.errorf("unmatched quote") |
|||
return |
|||
} |
|||
unq, err := unquoteC(p.s[1:i], rune(p.s[0])) |
|||
if err != nil { |
|||
p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) |
|||
return |
|||
} |
|||
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] |
|||
p.cur.unquoted = unq |
|||
default: |
|||
i := 0 |
|||
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { |
|||
i++ |
|||
} |
|||
if i == 0 { |
|||
p.errorf("unexpected byte %#x", p.s[0]) |
|||
return |
|||
} |
|||
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] |
|||
} |
|||
p.offset += len(p.cur.value) |
|||
} |
|||
|
|||
var ( |
|||
errBadUTF8 = errors.New("proto: bad UTF-8") |
|||
) |
|||
|
|||
func unquoteC(s string, quote rune) (string, error) { |
|||
// This is based on C++'s tokenizer.cc.
|
|||
// Despite its name, this is *not* parsing C syntax.
|
|||
// For instance, "\0" is an invalid quoted string.
|
|||
|
|||
// Avoid allocation in trivial cases.
|
|||
simple := true |
|||
for _, r := range s { |
|||
if r == '\\' || r == quote { |
|||
simple = false |
|||
break |
|||
} |
|||
} |
|||
if simple { |
|||
return s, nil |
|||
} |
|||
|
|||
buf := make([]byte, 0, 3*len(s)/2) |
|||
for len(s) > 0 { |
|||
r, n := utf8.DecodeRuneInString(s) |
|||
if r == utf8.RuneError && n == 1 { |
|||
return "", errBadUTF8 |
|||
} |
|||
s = s[n:] |
|||
if r != '\\' { |
|||
if r < utf8.RuneSelf { |
|||
buf = append(buf, byte(r)) |
|||
} else { |
|||
buf = append(buf, string(r)...) |
|||
} |
|||
continue |
|||
} |
|||
|
|||
ch, tail, err := unescape(s) |
|||
if err != nil { |
|||
return "", err |
|||
} |
|||
buf = append(buf, ch...) |
|||
s = tail |
|||
} |
|||
return string(buf), nil |
|||
} |
|||
|
|||
func unescape(s string) (ch string, tail string, err error) { |
|||
r, n := utf8.DecodeRuneInString(s) |
|||
if r == utf8.RuneError && n == 1 { |
|||
return "", "", errBadUTF8 |
|||
} |
|||
s = s[n:] |
|||
switch r { |
|||
case 'a': |
|||
return "\a", s, nil |
|||
case 'b': |
|||
return "\b", s, nil |
|||
case 'f': |
|||
return "\f", s, nil |
|||
case 'n': |
|||
return "\n", s, nil |
|||
case 'r': |
|||
return "\r", s, nil |
|||
case 't': |
|||
return "\t", s, nil |
|||
case 'v': |
|||
return "\v", s, nil |
|||
case '?': |
|||
return "?", s, nil // trigraph workaround
|
|||
case '\'', '"', '\\': |
|||
return string(r), s, nil |
|||
case '0', '1', '2', '3', '4', '5', '6', '7': |
|||
if len(s) < 2 { |
|||
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) |
|||
} |
|||
ss := string(r) + s[:2] |
|||
s = s[2:] |
|||
i, err := strconv.ParseUint(ss, 8, 8) |
|||
if err != nil { |
|||
return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) |
|||
} |
|||
return string([]byte{byte(i)}), s, nil |
|||
case 'x', 'X', 'u', 'U': |
|||
var n int |
|||
switch r { |
|||
case 'x', 'X': |
|||
n = 2 |
|||
case 'u': |
|||
n = 4 |
|||
case 'U': |
|||
n = 8 |
|||
} |
|||
if len(s) < n { |
|||
return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) |
|||
} |
|||
ss := s[:n] |
|||
s = s[n:] |
|||
i, err := strconv.ParseUint(ss, 16, 64) |
|||
if err != nil { |
|||
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) |
|||
} |
|||
if r == 'x' || r == 'X' { |
|||
return string([]byte{byte(i)}), s, nil |
|||
} |
|||
if i > utf8.MaxRune { |
|||
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) |
|||
} |
|||
return string(i), s, nil |
|||
} |
|||
return "", "", fmt.Errorf(`unknown escape \%c`, r) |
|||
} |
|||
|
|||
// Back off the parser by one token. Can only be done between calls to next().
|
|||
// It makes the next advance() a no-op.
|
|||
func (p *textParser) back() { p.backed = true } |
|||
|
|||
// Advances the parser and returns the new current token.
|
|||
func (p *textParser) next() *token { |
|||
if p.backed || p.done { |
|||
p.backed = false |
|||
return &p.cur |
|||
} |
|||
p.advance() |
|||
if p.done { |
|||
p.cur.value = "" |
|||
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { |
|||
// Look for multiple quoted strings separated by whitespace,
|
|||
// and concatenate them.
|
|||
cat := p.cur |
|||
for { |
|||
p.skipWhitespace() |
|||
if p.done || !isQuote(p.s[0]) { |
|||
break |
|||
} |
|||
p.advance() |
|||
if p.cur.err != nil { |
|||
return &p.cur |
|||
} |
|||
cat.value += " " + p.cur.value |
|||
cat.unquoted += p.cur.unquoted |
|||
} |
|||
p.done = false // parser may have seen EOF, but we want to return cat
|
|||
p.cur = cat |
|||
} |
|||
return &p.cur |
|||
} |
|||
|
|||
func (p *textParser) consumeToken(s string) error { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value != s { |
|||
p.back() |
|||
return p.errorf("expected %q, found %q", s, tok.value) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// Return a RequiredNotSetError indicating which required field was not set.
|
|||
func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { |
|||
st := sv.Type() |
|||
sprops := GetProperties(st) |
|||
for i := 0; i < st.NumField(); i++ { |
|||
if !isNil(sv.Field(i)) { |
|||
continue |
|||
} |
|||
|
|||
props := sprops.Prop[i] |
|||
if props.Required { |
|||
return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} |
|||
} |
|||
} |
|||
return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen
|
|||
} |
|||
|
|||
// Returns the index in the struct for the named field, as well as the parsed tag properties.
|
|||
func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { |
|||
i, ok := sprops.decoderOrigNames[name] |
|||
if ok { |
|||
return i, sprops.Prop[i], true |
|||
} |
|||
return -1, nil, false |
|||
} |
|||
|
|||
// Consume a ':' from the input stream (if the next token is a colon),
|
|||
// returning an error if a colon is needed but not present.
|
|||
func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value != ":" { |
|||
// Colon is optional when the field is a group or message.
|
|||
needColon := true |
|||
switch props.Wire { |
|||
case "group": |
|||
needColon = false |
|||
case "bytes": |
|||
// A "bytes" field is either a message, a string, or a repeated field;
|
|||
// those three become *T, *string and []T respectively, so we can check for
|
|||
// this field being a pointer to a non-string.
|
|||
if typ.Kind() == reflect.Ptr { |
|||
// *T or *string
|
|||
if typ.Elem().Kind() == reflect.String { |
|||
break |
|||
} |
|||
} else if typ.Kind() == reflect.Slice { |
|||
// []T or []*T
|
|||
if typ.Elem().Kind() != reflect.Ptr { |
|||
break |
|||
} |
|||
} else if typ.Kind() == reflect.String { |
|||
// The proto3 exception is for a string field,
|
|||
// which requires a colon.
|
|||
break |
|||
} |
|||
needColon = false |
|||
} |
|||
if needColon { |
|||
return p.errorf("expected ':', found %q", tok.value) |
|||
} |
|||
p.back() |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (p *textParser) readStruct(sv reflect.Value, terminator string) error { |
|||
st := sv.Type() |
|||
sprops := GetProperties(st) |
|||
reqCount := sprops.reqCount |
|||
var reqFieldErr error |
|||
fieldSet := make(map[string]bool) |
|||
// A struct is a sequence of "name: value", terminated by one of
|
|||
// '>' or '}', or the end of the input. A name may also be
|
|||
// "[extension]" or "[type/url]".
|
|||
//
|
|||
// The whole struct can also be an expanded Any message, like:
|
|||
// [type/url] < ... struct contents ... >
|
|||
for { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value == terminator { |
|||
break |
|||
} |
|||
if tok.value == "[" { |
|||
// Looks like an extension or an Any.
|
|||
//
|
|||
// TODO: Check whether we need to handle
|
|||
// namespace rooted names (e.g. ".something.Foo").
|
|||
extName, err := p.consumeExtName() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
if s := strings.LastIndex(extName, "/"); s >= 0 { |
|||
// If it contains a slash, it's an Any type URL.
|
|||
messageName := extName[s+1:] |
|||
mt := MessageType(messageName) |
|||
if mt == nil { |
|||
return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) |
|||
} |
|||
tok = p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
// consume an optional colon
|
|||
if tok.value == ":" { |
|||
tok = p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
} |
|||
var terminator string |
|||
switch tok.value { |
|||
case "<": |
|||
terminator = ">" |
|||
case "{": |
|||
terminator = "}" |
|||
default: |
|||
return p.errorf("expected '{' or '<', found %q", tok.value) |
|||
} |
|||
v := reflect.New(mt.Elem()) |
|||
if pe := p.readStruct(v.Elem(), terminator); pe != nil { |
|||
return pe |
|||
} |
|||
b, err := Marshal(v.Interface().(Message)) |
|||
if err != nil { |
|||
return p.errorf("failed to marshal message of type %q: %v", messageName, err) |
|||
} |
|||
if fieldSet["type_url"] { |
|||
return p.errorf(anyRepeatedlyUnpacked, "type_url") |
|||
} |
|||
if fieldSet["value"] { |
|||
return p.errorf(anyRepeatedlyUnpacked, "value") |
|||
} |
|||
sv.FieldByName("TypeUrl").SetString(extName) |
|||
sv.FieldByName("Value").SetBytes(b) |
|||
fieldSet["type_url"] = true |
|||
fieldSet["value"] = true |
|||
continue |
|||
} |
|||
|
|||
var desc *ExtensionDesc |
|||
// This could be faster, but it's functional.
|
|||
// TODO: Do something smarter than a linear scan.
|
|||
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { |
|||
if d.Name == extName { |
|||
desc = d |
|||
break |
|||
} |
|||
} |
|||
if desc == nil { |
|||
return p.errorf("unrecognized extension %q", extName) |
|||
} |
|||
|
|||
props := &Properties{} |
|||
props.Parse(desc.Tag) |
|||
|
|||
typ := reflect.TypeOf(desc.ExtensionType) |
|||
if err := p.checkForColon(props, typ); err != nil { |
|||
return err |
|||
} |
|||
|
|||
rep := desc.repeated() |
|||
|
|||
// Read the extension structure, and set it in
|
|||
// the value we're constructing.
|
|||
var ext reflect.Value |
|||
if !rep { |
|||
ext = reflect.New(typ).Elem() |
|||
} else { |
|||
ext = reflect.New(typ.Elem()).Elem() |
|||
} |
|||
if err := p.readAny(ext, props); err != nil { |
|||
if _, ok := err.(*RequiredNotSetError); !ok { |
|||
return err |
|||
} |
|||
reqFieldErr = err |
|||
} |
|||
ep := sv.Addr().Interface().(Message) |
|||
if !rep { |
|||
SetExtension(ep, desc, ext.Interface()) |
|||
} else { |
|||
old, err := GetExtension(ep, desc) |
|||
var sl reflect.Value |
|||
if err == nil { |
|||
sl = reflect.ValueOf(old) // existing slice
|
|||
} else { |
|||
sl = reflect.MakeSlice(typ, 0, 1) |
|||
} |
|||
sl = reflect.Append(sl, ext) |
|||
SetExtension(ep, desc, sl.Interface()) |
|||
} |
|||
if err := p.consumeOptionalSeparator(); err != nil { |
|||
return err |
|||
} |
|||
continue |
|||
} |
|||
|
|||
// This is a normal, non-extension field.
|
|||
name := tok.value |
|||
var dst reflect.Value |
|||
fi, props, ok := structFieldByName(sprops, name) |
|||
if ok { |
|||
dst = sv.Field(fi) |
|||
} else if oop, ok := sprops.OneofTypes[name]; ok { |
|||
// It is a oneof.
|
|||
props = oop.Prop |
|||
nv := reflect.New(oop.Type.Elem()) |
|||
dst = nv.Elem().Field(0) |
|||
field := sv.Field(oop.Field) |
|||
if !field.IsNil() { |
|||
return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) |
|||
} |
|||
field.Set(nv) |
|||
} |
|||
if !dst.IsValid() { |
|||
return p.errorf("unknown field name %q in %v", name, st) |
|||
} |
|||
|
|||
if dst.Kind() == reflect.Map { |
|||
// Consume any colon.
|
|||
if err := p.checkForColon(props, dst.Type()); err != nil { |
|||
return err |
|||
} |
|||
|
|||
// Construct the map if it doesn't already exist.
|
|||
if dst.IsNil() { |
|||
dst.Set(reflect.MakeMap(dst.Type())) |
|||
} |
|||
key := reflect.New(dst.Type().Key()).Elem() |
|||
val := reflect.New(dst.Type().Elem()).Elem() |
|||
|
|||
// The map entry should be this sequence of tokens:
|
|||
// < key : KEY value : VALUE >
|
|||
// However, implementations may omit key or value, and technically
|
|||
// we should support them in any order. See b/28924776 for a time
|
|||
// this went wrong.
|
|||
|
|||
tok := p.next() |
|||
var terminator string |
|||
switch tok.value { |
|||
case "<": |
|||
terminator = ">" |
|||
case "{": |
|||
terminator = "}" |
|||
default: |
|||
return p.errorf("expected '{' or '<', found %q", tok.value) |
|||
} |
|||
for { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value == terminator { |
|||
break |
|||
} |
|||
switch tok.value { |
|||
case "key": |
|||
if err := p.consumeToken(":"); err != nil { |
|||
return err |
|||
} |
|||
if err := p.readAny(key, props.MapKeyProp); err != nil { |
|||
return err |
|||
} |
|||
if err := p.consumeOptionalSeparator(); err != nil { |
|||
return err |
|||
} |
|||
case "value": |
|||
if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { |
|||
return err |
|||
} |
|||
if err := p.readAny(val, props.MapValProp); err != nil { |
|||
return err |
|||
} |
|||
if err := p.consumeOptionalSeparator(); err != nil { |
|||
return err |
|||
} |
|||
default: |
|||
p.back() |
|||
return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) |
|||
} |
|||
} |
|||
|
|||
dst.SetMapIndex(key, val) |
|||
continue |
|||
} |
|||
|
|||
// Check that it's not already set if it's not a repeated field.
|
|||
if !props.Repeated && fieldSet[name] { |
|||
return p.errorf("non-repeated field %q was repeated", name) |
|||
} |
|||
|
|||
if err := p.checkForColon(props, dst.Type()); err != nil { |
|||
return err |
|||
} |
|||
|
|||
// Parse into the field.
|
|||
fieldSet[name] = true |
|||
if err := p.readAny(dst, props); err != nil { |
|||
if _, ok := err.(*RequiredNotSetError); !ok { |
|||
return err |
|||
} |
|||
reqFieldErr = err |
|||
} |
|||
if props.Required { |
|||
reqCount-- |
|||
} |
|||
|
|||
if err := p.consumeOptionalSeparator(); err != nil { |
|||
return err |
|||
} |
|||
|
|||
} |
|||
|
|||
if reqCount > 0 { |
|||
return p.missingRequiredFieldError(sv) |
|||
} |
|||
return reqFieldErr |
|||
} |
|||
|
|||
// consumeExtName consumes extension name or expanded Any type URL and the
|
|||
// following ']'. It returns the name or URL consumed.
|
|||
func (p *textParser) consumeExtName() (string, error) { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return "", tok.err |
|||
} |
|||
|
|||
// If extension name or type url is quoted, it's a single token.
|
|||
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { |
|||
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) |
|||
if err != nil { |
|||
return "", err |
|||
} |
|||
return name, p.consumeToken("]") |
|||
} |
|||
|
|||
// Consume everything up to "]"
|
|||
var parts []string |
|||
for tok.value != "]" { |
|||
parts = append(parts, tok.value) |
|||
tok = p.next() |
|||
if tok.err != nil { |
|||
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) |
|||
} |
|||
if p.done && tok.value != "]" { |
|||
return "", p.errorf("unclosed type_url or extension name") |
|||
} |
|||
} |
|||
return strings.Join(parts, ""), nil |
|||
} |
|||
|
|||
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
|||
// It is used in readStruct to provide backward compatibility.
|
|||
func (p *textParser) consumeOptionalSeparator() error { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value != ";" && tok.value != "," { |
|||
p.back() |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (p *textParser) readAny(v reflect.Value, props *Properties) error { |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value == "" { |
|||
return p.errorf("unexpected EOF") |
|||
} |
|||
|
|||
switch fv := v; fv.Kind() { |
|||
case reflect.Slice: |
|||
at := v.Type() |
|||
if at.Elem().Kind() == reflect.Uint8 { |
|||
// Special case for []byte
|
|||
if tok.value[0] != '"' && tok.value[0] != '\'' { |
|||
// Deliberately written out here, as the error after
|
|||
// this switch statement would write "invalid []byte: ...",
|
|||
// which is not as user-friendly.
|
|||
return p.errorf("invalid string: %v", tok.value) |
|||
} |
|||
bytes := []byte(tok.unquoted) |
|||
fv.Set(reflect.ValueOf(bytes)) |
|||
return nil |
|||
} |
|||
// Repeated field.
|
|||
if tok.value == "[" { |
|||
// Repeated field with list notation, like [1,2,3].
|
|||
for { |
|||
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) |
|||
err := p.readAny(fv.Index(fv.Len()-1), props) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
tok := p.next() |
|||
if tok.err != nil { |
|||
return tok.err |
|||
} |
|||
if tok.value == "]" { |
|||
break |
|||
} |
|||
if tok.value != "," { |
|||
return p.errorf("Expected ']' or ',' found %q", tok.value) |
|||
} |
|||
} |
|||
return nil |
|||
} |
|||
// One value of the repeated field.
|
|||
p.back() |
|||
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) |
|||
return p.readAny(fv.Index(fv.Len()-1), props) |
|||
case reflect.Bool: |
|||
// true/1/t/True or false/f/0/False.
|
|||
switch tok.value { |
|||
case "true", "1", "t", "True": |
|||
fv.SetBool(true) |
|||
return nil |
|||
case "false", "0", "f", "False": |
|||
fv.SetBool(false) |
|||
return nil |
|||
} |
|||
case reflect.Float32, reflect.Float64: |
|||
v := tok.value |
|||
// Ignore 'f' for compatibility with output generated by C++, but don't
|
|||
// remove 'f' when the value is "-inf" or "inf".
|
|||
if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { |
|||
v = v[:len(v)-1] |
|||
} |
|||
if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { |
|||
fv.SetFloat(f) |
|||
return nil |
|||
} |
|||
case reflect.Int32: |
|||
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { |
|||
fv.SetInt(x) |
|||
return nil |
|||
} |
|||
|
|||
if len(props.Enum) == 0 { |
|||
break |
|||
} |
|||
m, ok := enumValueMaps[props.Enum] |
|||
if !ok { |
|||
break |
|||
} |
|||
x, ok := m[tok.value] |
|||
if !ok { |
|||
break |
|||
} |
|||
fv.SetInt(int64(x)) |
|||
return nil |
|||
case reflect.Int64: |
|||
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { |
|||
fv.SetInt(x) |
|||
return nil |
|||
} |
|||
|
|||
case reflect.Ptr: |
|||
// A basic field (indirected through pointer), or a repeated message/group
|
|||
p.back() |
|||
fv.Set(reflect.New(fv.Type().Elem())) |
|||
return p.readAny(fv.Elem(), props) |
|||
case reflect.String: |
|||
if tok.value[0] == '"' || tok.value[0] == '\'' { |
|||
fv.SetString(tok.unquoted) |
|||
return nil |
|||
} |
|||
case reflect.Struct: |
|||
var terminator string |
|||
switch tok.value { |
|||
case "{": |
|||
terminator = "}" |
|||
case "<": |
|||
terminator = ">" |
|||
default: |
|||
return p.errorf("expected '{' or '<', found %q", tok.value) |
|||
} |
|||
// TODO: Handle nested messages which implement encoding.TextUnmarshaler.
|
|||
return p.readStruct(fv, terminator) |
|||
case reflect.Uint32: |
|||
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { |
|||
fv.SetUint(uint64(x)) |
|||
return nil |
|||
} |
|||
case reflect.Uint64: |
|||
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { |
|||
fv.SetUint(x) |
|||
return nil |
|||
} |
|||
} |
|||
return p.errorf("invalid %v: %v", v.Type(), tok.value) |
|||
} |
|||
|
|||
// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
|
|||
// before starting to unmarshal, so any existing data in pb is always removed.
|
|||
// If a required field is not set and no other error occurs,
|
|||
// UnmarshalText returns *RequiredNotSetError.
|
|||
func UnmarshalText(s string, pb Message) error { |
|||
if um, ok := pb.(encoding.TextUnmarshaler); ok { |
|||
return um.UnmarshalText([]byte(s)) |
|||
} |
|||
pb.Reset() |
|||
v := reflect.ValueOf(pb) |
|||
return newTextParser(s).readStruct(v.Elem(), "") |
|||
} |
@ -0,0 +1,2 @@ |
|||
# github.com/golang/protobuf v1.3.3 |
|||
github.com/golang/protobuf/proto |
Write
Preview
Loading…
Cancel
Save
Reference in new issue