Merge pull request #83 from prometheus/godep-vendoring
Use godep with import rewriting for vendoring.
This commit is contained in:
commit
a6c5e0f955
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/client_golang",
|
||||||
|
"GoVersion": "go1.4.1",
|
||||||
|
"Packages": [
|
||||||
|
"./..."
|
||||||
|
],
|
||||||
|
"Deps": [
|
||||||
|
{
|
||||||
|
"ImportPath": "bitbucket.org/ww/goautoneg",
|
||||||
|
"Comment": "null-5",
|
||||||
|
"Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/beorn7/perks/quantile",
|
||||||
|
"Rev": "b965b613227fddccbfffe13eae360ed3fa822f8d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/proto",
|
||||||
|
"Rev": "c22ae3cf020a21ebb7ae566dccbe90fc8ea4f9ea"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/ext",
|
||||||
|
"Rev": "ba7d65ac66e9da93a714ca18f6d1bc7a0c09100c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/client_model/go",
|
||||||
|
"Comment": "model-0.0.2-12-gfa8ad6f",
|
||||||
|
"Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/procfs",
|
||||||
|
"Rev": "6c34ef819e19b4e16f410100ace4aa006f0e3bf8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
This directory tree is generated automatically by godep.
|
||||||
|
|
||||||
|
Please do not edit.
|
||||||
|
|
||||||
|
See https://github.com/tools/godep for more information.
|
|
@ -0,0 +1,2 @@
|
||||||
|
/pkg
|
||||||
|
/bin
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/beorn7/perks/quantile"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/beorn7/perks/quantile"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Example_simple() {
|
func Example_simple() {
|
|
@ -0,0 +1,43 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
install:
|
||||||
|
go install
|
||||||
|
|
||||||
|
test: install generate-test-pbs
|
||||||
|
go test
|
||||||
|
|
||||||
|
|
||||||
|
generate-test-pbs:
|
||||||
|
make install
|
||||||
|
make -C testdata
|
||||||
|
make -C proto3_proto
|
||||||
|
make
|
2059
Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go
generated
vendored
Normal file
2059
Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,197 @@
|
||||||
|
// 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: MessageSet and RawMessage.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clone returns a deep copy of a protocol buffer.
|
||||||
|
func Clone(pb Message) Message {
|
||||||
|
in := reflect.ValueOf(pb)
|
||||||
|
if in.IsNil() {
|
||||||
|
return pb
|
||||||
|
}
|
||||||
|
|
||||||
|
out := reflect.New(in.Type().Elem())
|
||||||
|
// out is empty so a merge is a deep copy.
|
||||||
|
mergeStruct(out.Elem(), in.Elem())
|
||||||
|
return out.Interface().(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) {
|
||||||
|
in := reflect.ValueOf(src)
|
||||||
|
out := reflect.ValueOf(dst)
|
||||||
|
if out.IsNil() {
|
||||||
|
panic("proto: nil destination")
|
||||||
|
}
|
||||||
|
if in.Type() != out.Type() {
|
||||||
|
// Explicit test prior to mergeStruct so that mistyped nils will fail
|
||||||
|
panic("proto: type mismatch")
|
||||||
|
}
|
||||||
|
if in.IsNil() {
|
||||||
|
// Merging nil into non-nil is a quiet no-op
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mergeStruct(out.Elem(), in.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeStruct(out, in reflect.Value) {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
if emIn, ok := in.Addr().Interface().(extendableProto); ok {
|
||||||
|
emOut := out.Addr().Interface().(extendableProto)
|
||||||
|
mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
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...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeAny(out, in reflect.Value) {
|
||||||
|
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:
|
||||||
|
out.Set(in)
|
||||||
|
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))
|
||||||
|
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())
|
||||||
|
case reflect.Slice:
|
||||||
|
if in.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if in.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
|
// []byte is a scalar bytes field, not a repeated field.
|
||||||
|
// 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))
|
||||||
|
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))
|
||||||
|
eOut.value = v.Interface()
|
||||||
|
}
|
||||||
|
if eIn.enc != nil {
|
||||||
|
eOut.enc = make([]byte, len(eIn.enc))
|
||||||
|
copy(eOut.enc, eIn.enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
out[extNum] = eOut
|
||||||
|
}
|
||||||
|
}
|
226
Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go
generated
vendored
Normal file
226
Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package proto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
pb "./testdata"
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cloneTestMessage = &pb.MyMessage{
|
||||||
|
Count: proto.Int32(42),
|
||||||
|
Name: proto.String("Dave"),
|
||||||
|
Pet: []string{"bunny", "kitty", "horsey"},
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("niles"),
|
||||||
|
Port: proto.Int32(9099),
|
||||||
|
Connected: proto.Bool(true),
|
||||||
|
},
|
||||||
|
Others: []*pb.OtherMessage{
|
||||||
|
{
|
||||||
|
Value: []byte("some bytes"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: proto.Int32(6),
|
||||||
|
},
|
||||||
|
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ext := &pb.Ext{
|
||||||
|
Data: proto.String("extension"),
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil {
|
||||||
|
panic("SetExtension: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClone(t *testing.T) {
|
||||||
|
m := proto.Clone(cloneTestMessage).(*pb.MyMessage)
|
||||||
|
if !proto.Equal(m, cloneTestMessage) {
|
||||||
|
t.Errorf("Clone(%v) = %v", cloneTestMessage, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify it was a deep copy.
|
||||||
|
*m.Inner.Port++
|
||||||
|
if proto.Equal(m, cloneTestMessage) {
|
||||||
|
t.Error("Mutating clone changed the original")
|
||||||
|
}
|
||||||
|
// Byte fields and repeated fields should be copied.
|
||||||
|
if &m.Pet[0] == &cloneTestMessage.Pet[0] {
|
||||||
|
t.Error("Pet: repeated field not copied")
|
||||||
|
}
|
||||||
|
if &m.Others[0] == &cloneTestMessage.Others[0] {
|
||||||
|
t.Error("Others: repeated field not copied")
|
||||||
|
}
|
||||||
|
if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] {
|
||||||
|
t.Error("Others[0].Value: bytes field not copied")
|
||||||
|
}
|
||||||
|
if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] {
|
||||||
|
t.Error("RepBytes: repeated field not copied")
|
||||||
|
}
|
||||||
|
if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] {
|
||||||
|
t.Error("RepBytes[0]: bytes field not copied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCloneNil(t *testing.T) {
|
||||||
|
var m *pb.MyMessage
|
||||||
|
if c := proto.Clone(m); !proto.Equal(m, c) {
|
||||||
|
t.Errorf("Clone(%v) = %v", m, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mergeTests = []struct {
|
||||||
|
src, dst, want proto.Message
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
src: &pb.MyMessage{
|
||||||
|
Count: proto.Int32(42),
|
||||||
|
},
|
||||||
|
dst: &pb.MyMessage{
|
||||||
|
Name: proto.String("Dave"),
|
||||||
|
},
|
||||||
|
want: &pb.MyMessage{
|
||||||
|
Count: proto.Int32(42),
|
||||||
|
Name: proto.String("Dave"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: &pb.MyMessage{
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("hey"),
|
||||||
|
Connected: proto.Bool(true),
|
||||||
|
},
|
||||||
|
Pet: []string{"horsey"},
|
||||||
|
Others: []*pb.OtherMessage{
|
||||||
|
{
|
||||||
|
Value: []byte("some bytes"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dst: &pb.MyMessage{
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("niles"),
|
||||||
|
Port: proto.Int32(9099),
|
||||||
|
},
|
||||||
|
Pet: []string{"bunny", "kitty"},
|
||||||
|
Others: []*pb.OtherMessage{
|
||||||
|
{
|
||||||
|
Key: proto.Int64(31415926535),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Explicitly test a src=nil field
|
||||||
|
Inner: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &pb.MyMessage{
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("hey"),
|
||||||
|
Connected: proto.Bool(true),
|
||||||
|
Port: proto.Int32(9099),
|
||||||
|
},
|
||||||
|
Pet: []string{"bunny", "kitty", "horsey"},
|
||||||
|
Others: []*pb.OtherMessage{
|
||||||
|
{
|
||||||
|
Key: proto.Int64(31415926535),
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
Value: []byte("some bytes"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: &pb.MyMessage{
|
||||||
|
RepBytes: [][]byte{[]byte("wow")},
|
||||||
|
},
|
||||||
|
dst: &pb.MyMessage{
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: proto.Int32(6),
|
||||||
|
},
|
||||||
|
RepBytes: [][]byte{[]byte("sham")},
|
||||||
|
},
|
||||||
|
want: &pb.MyMessage{
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: proto.Int32(6),
|
||||||
|
},
|
||||||
|
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Check that a scalar bytes field replaces rather than appends.
|
||||||
|
{
|
||||||
|
src: &pb.OtherMessage{Value: []byte("foo")},
|
||||||
|
dst: &pb.OtherMessage{Value: []byte("bar")},
|
||||||
|
want: &pb.OtherMessage{Value: []byte("foo")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: &pb.MessageWithMap{
|
||||||
|
NameMapping: map[int32]string{6: "Nigel"},
|
||||||
|
MsgMapping: map[int64]*pb.FloatingPoint{
|
||||||
|
0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)},
|
||||||
|
},
|
||||||
|
ByteMapping: map[bool][]byte{true: []byte("wowsa")},
|
||||||
|
},
|
||||||
|
dst: &pb.MessageWithMap{
|
||||||
|
NameMapping: map[int32]string{
|
||||||
|
6: "Bruce", // should be overwritten
|
||||||
|
7: "Andrew",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &pb.MessageWithMap{
|
||||||
|
NameMapping: map[int32]string{
|
||||||
|
6: "Nigel",
|
||||||
|
7: "Andrew",
|
||||||
|
},
|
||||||
|
MsgMapping: map[int64]*pb.FloatingPoint{
|
||||||
|
0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)},
|
||||||
|
},
|
||||||
|
ByteMapping: map[bool][]byte{true: []byte("wowsa")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerge(t *testing.T) {
|
||||||
|
for _, m := range mergeTests {
|
||||||
|
got := proto.Clone(m.dst)
|
||||||
|
proto.Merge(got, m.src)
|
||||||
|
if !proto.Equal(got, m.want) {
|
||||||
|
t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,821 @@
|
||||||
|
// 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"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errOverflow is returned when an integer is too large to be represented.
|
||||||
|
var errOverflow = errors.New("proto: integer overflow")
|
||||||
|
|
||||||
|
// The fundamental decoders that interpret bytes on the wire.
|
||||||
|
// Those that take integer types all return uint64 and are
|
||||||
|
// therefore of type valueDecoder.
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// x, n already 0
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// x, err already 0
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not ValueDecoders: they produce an array of bytes or a string.
|
||||||
|
// bytes, embedded messages
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||||
|
// If the protocol buffer has extensions, and the field matches, add it as an extension.
|
||||||
|
// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
|
||||||
|
func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
|
||||||
|
oi := o.index
|
||||||
|
|
||||||
|
err := o.skip(t, tag, wire)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unrecField.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr := structPointer_Bytes(base, unrecField)
|
||||||
|
|
||||||
|
// Add the skipped field to struct field
|
||||||
|
obuf := o.buf
|
||||||
|
|
||||||
|
o.buf = *ptr
|
||||||
|
o.EncodeVarint(uint64(tag<<3 | wire))
|
||||||
|
*ptr = append(o.buf, obuf[oi:o.index]...)
|
||||||
|
|
||||||
|
o.buf = obuf
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||||
|
func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
|
||||||
|
|
||||||
|
var u uint64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch wire {
|
||||||
|
case WireVarint:
|
||||||
|
_, err = o.DecodeVarint()
|
||||||
|
case WireFixed64:
|
||||||
|
_, err = o.DecodeFixed64()
|
||||||
|
case WireBytes:
|
||||||
|
_, err = o.DecodeRawBytes(false)
|
||||||
|
case WireFixed32:
|
||||||
|
_, err = o.DecodeFixed32()
|
||||||
|
case WireStartGroup:
|
||||||
|
for {
|
||||||
|
u, err = o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fwire := int(u & 0x7)
|
||||||
|
if fwire == WireEndGroup {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ftag := int(u >> 3)
|
||||||
|
err = o.skip(t, ftag, fwire)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is the interface representing objects that can
|
||||||
|
// unmarshal themselves. The method should reset the receiver before
|
||||||
|
// decoding starts. The argument points to data that may be
|
||||||
|
// overwritten, so implementations should not keep references to the
|
||||||
|
// buffer.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
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()
|
||||||
|
return UnmarshalMerge(buf, 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 the object can unmarshal itself, let it.
|
||||||
|
if u, ok := pb.(Unmarshaler); ok {
|
||||||
|
return u.Unmarshal(buf)
|
||||||
|
}
|
||||||
|
return NewBuffer(buf).Unmarshal(pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (p *Buffer) Unmarshal(pb Message) error {
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if u, ok := pb.(Unmarshaler); ok {
|
||||||
|
err := u.Unmarshal(p.buf[p.index:])
|
||||||
|
p.index = len(p.buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, base, err := getbase(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base)
|
||||||
|
|
||||||
|
if collectStats {
|
||||||
|
stats.Decode++
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalType does the work of unmarshaling a structure.
|
||||||
|
func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
|
||||||
|
var state errorState
|
||||||
|
required, reqFields := prop.reqCount, uint64(0)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for err == nil && o.index < len(o.buf) {
|
||||||
|
oi := o.index
|
||||||
|
var u uint64
|
||||||
|
u, err = o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
wire := int(u & 0x7)
|
||||||
|
if wire == WireEndGroup {
|
||||||
|
if is_group {
|
||||||
|
return nil // input is satisfied
|
||||||
|
}
|
||||||
|
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
|
||||||
|
}
|
||||||
|
tag := int(u >> 3)
|
||||||
|
if tag <= 0 {
|
||||||
|
return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
|
||||||
|
}
|
||||||
|
fieldnum, ok := prop.decoderTags.get(tag)
|
||||||
|
if !ok {
|
||||||
|
// Maybe it's an extension?
|
||||||
|
if prop.extendable {
|
||||||
|
if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) {
|
||||||
|
if err = o.skip(st, tag, wire); err == nil {
|
||||||
|
ext := e.ExtensionMap()[int32(tag)] // may be missing
|
||||||
|
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
|
||||||
|
e.ExtensionMap()[int32(tag)] = ext
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := prop.Prop[fieldnum]
|
||||||
|
|
||||||
|
if p.dec == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dec := p.dec
|
||||||
|
if wire != WireStartGroup && wire != p.WireType {
|
||||||
|
if wire == WireBytes && p.packedDec != nil {
|
||||||
|
// a packable field
|
||||||
|
dec = p.packedDec
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decErr := dec(o, p, base)
|
||||||
|
if decErr != nil && !state.shouldContinue(decErr, p) {
|
||||||
|
err = decErr
|
||||||
|
}
|
||||||
|
if err == nil && p.Required {
|
||||||
|
// Successfully decoded a required field.
|
||||||
|
if tag <= 64 {
|
||||||
|
// use bitmap for fields 1-64 to catch field reuse.
|
||||||
|
var mask uint64 = 1 << uint64(tag-1)
|
||||||
|
if reqFields&mask == 0 {
|
||||||
|
// new required field
|
||||||
|
reqFields |= mask
|
||||||
|
required--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is imprecise. It can be fooled by a required field
|
||||||
|
// with a tag > 64 that is encoded twice; that's very rare.
|
||||||
|
// A fully correct implementation would require allocating
|
||||||
|
// a data structure, which we would like to avoid.
|
||||||
|
required--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if is_group {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
if state.err != nil {
|
||||||
|
return state.err
|
||||||
|
}
|
||||||
|
if required > 0 {
|
||||||
|
// Not enough information to determine the exact field. If we use extra
|
||||||
|
// CPU, we could determine the field only if the missing required field
|
||||||
|
// has a tag <= 64 and we check reqFields.
|
||||||
|
return &RequiredNotSetError{"{Unknown}"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual type decoders
|
||||||
|
// For each,
|
||||||
|
// u is the decoded value,
|
||||||
|
// v is a pointer to the field (pointer) in the struct
|
||||||
|
|
||||||
|
// Sizes of the pools to allocate inside the Buffer.
|
||||||
|
// The goal is modest amortization and allocation
|
||||||
|
// on at least 16-byte boundaries.
|
||||||
|
const (
|
||||||
|
boolPoolSize = 16
|
||||||
|
uint32PoolSize = 8
|
||||||
|
uint64PoolSize = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode a bool.
|
||||||
|
func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(o.bools) == 0 {
|
||||||
|
o.bools = make([]bool, boolPoolSize)
|
||||||
|
}
|
||||||
|
o.bools[0] = u != 0
|
||||||
|
*structPointer_Bool(base, p.field) = &o.bools[0]
|
||||||
|
o.bools = o.bools[1:]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_BoolVal(base, p.field) = u != 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an int32.
|
||||||
|
func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an int64.
|
||||||
|
func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word64_Set(structPointer_Word64(base, p.field), o, u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word64Val_Set(structPointer_Word64Val(base, p.field), o, u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a string.
|
||||||
|
func (o *Buffer) dec_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_String(base, p.field) = &s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_StringVal(base, p.field) = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bytes ([]byte).
|
||||||
|
func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
|
||||||
|
b, err := o.DecodeRawBytes(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_Bytes(base, p.field) = b
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bools ([]bool).
|
||||||
|
func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_BoolSlice(base, p.field)
|
||||||
|
*v = append(*v, u != 0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bools ([]bool) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_BoolSlice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded bools
|
||||||
|
|
||||||
|
y := *v
|
||||||
|
for i := 0; i < nb; i++ {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
y = append(y, u != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = y
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int32s ([]int32).
|
||||||
|
func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
structPointer_Word32Slice(base, p.field).Append(uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int32s ([]int32) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_Word32Slice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded int32s
|
||||||
|
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
for o.index < fin {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Append(uint32(u))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int64s ([]int64).
|
||||||
|
func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
structPointer_Word64Slice(base, p.field).Append(u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int64s ([]int64) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_Word64Slice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded int64s
|
||||||
|
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
for o.index < fin {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Append(u)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of strings ([]string).
|
||||||
|
func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_StringSlice(base, p.field)
|
||||||
|
*v = append(*v, s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of slice of bytes ([][]byte).
|
||||||
|
func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
|
||||||
|
b, err := o.DecodeRawBytes(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_BytesSlice(base, p.field)
|
||||||
|
*v = append(*v, b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a map field.
|
||||||
|
func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
|
||||||
|
raw, err := o.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oi := o.index // index at the end of this map entry
|
||||||
|
o.index -= len(raw) // move buffer back to start of map entry
|
||||||
|
|
||||||
|
mptr := structPointer_Map(base, p.field, p.mtype) // *map[K]V
|
||||||
|
if mptr.Elem().IsNil() {
|
||||||
|
mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
|
||||||
|
}
|
||||||
|
v := mptr.Elem() // map[K]V
|
||||||
|
|
||||||
|
// Prepare addressable doubly-indirect placeholders for the key and value types.
|
||||||
|
// See enc_new_map for why.
|
||||||
|
keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
|
||||||
|
keybase := toStructPointer(keyptr.Addr()) // **K
|
||||||
|
|
||||||
|
var valbase structPointer
|
||||||
|
var valptr reflect.Value
|
||||||
|
switch p.mtype.Elem().Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
// []byte
|
||||||
|
var dummy []byte
|
||||||
|
valptr = reflect.ValueOf(&dummy) // *[]byte
|
||||||
|
valbase = toStructPointer(valptr) // *[]byte
|
||||||
|
case reflect.Ptr:
|
||||||
|
// message; valptr is **Msg; need to allocate the intermediate pointer
|
||||||
|
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||||
|
valptr.Set(reflect.New(valptr.Type().Elem()))
|
||||||
|
valbase = toStructPointer(valptr)
|
||||||
|
default:
|
||||||
|
// everything else
|
||||||
|
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||||
|
valbase = toStructPointer(valptr.Addr()) // **V
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode.
|
||||||
|
// This parses a restricted wire format, namely the encoding of a message
|
||||||
|
// with two fields. See enc_new_map for the format.
|
||||||
|
for o.index < oi {
|
||||||
|
// tagcode for key and value properties are always a single byte
|
||||||
|
// because they have tags 1 and 2.
|
||||||
|
tagcode := o.buf[o.index]
|
||||||
|
o.index++
|
||||||
|
switch tagcode {
|
||||||
|
case p.mkeyprop.tagcode[0]:
|
||||||
|
if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case p.mvalprop.tagcode[0]:
|
||||||
|
if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO: Should we silently skip this instead?
|
||||||
|
return fmt.Errorf("proto: bad map data tag %d", raw[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v.SetMapIndex(keyptr.Elem(), valptr.Elem())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a group.
|
||||||
|
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
|
||||||
|
bas := structPointer_GetStructPointer(base, p.field)
|
||||||
|
if structPointer_IsNil(bas) {
|
||||||
|
// allocate new nested message
|
||||||
|
bas = toStructPointer(reflect.New(p.stype))
|
||||||
|
structPointer_SetStructPointer(base, p.field, bas)
|
||||||
|
}
|
||||||
|
return o.unmarshalType(p.stype, p.sprop, true, bas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an embedded message.
|
||||||
|
func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
|
||||||
|
raw, e := o.DecodeRawBytes(false)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
bas := structPointer_GetStructPointer(base, p.field)
|
||||||
|
if structPointer_IsNil(bas) {
|
||||||
|
// allocate new nested message
|
||||||
|
bas = toStructPointer(reflect.New(p.stype))
|
||||||
|
structPointer_SetStructPointer(base, p.field, bas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if p.isUnmarshaler {
|
||||||
|
iv := structPointer_Interface(bas, p.stype)
|
||||||
|
return iv.(Unmarshaler).Unmarshal(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
obuf := o.buf
|
||||||
|
oi := o.index
|
||||||
|
o.buf = raw
|
||||||
|
o.index = 0
|
||||||
|
|
||||||
|
err = o.unmarshalType(p.stype, p.sprop, false, bas)
|
||||||
|
o.buf = obuf
|
||||||
|
o.index = oi
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of embedded messages.
|
||||||
|
func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
|
||||||
|
return o.dec_slice_struct(p, false, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of embedded groups.
|
||||||
|
func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
|
||||||
|
return o.dec_slice_struct(p, true, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of structs ([]*struct).
|
||||||
|
func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
|
||||||
|
v := reflect.New(p.stype)
|
||||||
|
bas := toStructPointer(v)
|
||||||
|
structPointer_StructPointerSlice(base, p.field).Append(bas)
|
||||||
|
|
||||||
|
if is_group {
|
||||||
|
err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := o.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if p.isUnmarshaler {
|
||||||
|
iv := v.Interface()
|
||||||
|
return iv.(Unmarshaler).Unmarshal(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
obuf := o.buf
|
||||||
|
oi := o.index
|
||||||
|
o.buf = raw
|
||||||
|
o.index = 0
|
||||||
|
|
||||||
|
err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||||
|
|
||||||
|
o.buf = obuf
|
||||||
|
o.index = oi
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
1283
Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go
generated
vendored
Normal file
1283
Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,256 @@
|
||||||
|
// 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.
|
||||||
|
// TODO: MessageSet.
|
||||||
|
|
||||||
|
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.
|
||||||
|
- Two repeated fields are equal iff their lengths are the same,
|
||||||
|
and their corresponding elements are equal (a "bytes" field,
|
||||||
|
although represented by []byte, is not a repeated field)
|
||||||
|
- 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.
|
||||||
|
- 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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
b1, ok := f1.Interface().(raw)
|
||||||
|
if ok {
|
||||||
|
b2 := f2.Interface().(raw)
|
||||||
|
// RawMessage
|
||||||
|
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f1, f2 = f1.Elem(), f2.Elem()
|
||||||
|
}
|
||||||
|
if !equalAny(f1, f2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
|
||||||
|
em2 := v2.FieldByName("XXX_extensions")
|
||||||
|
if !equalExtensions(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()
|
||||||
|
if !bytes.Equal(u1, u2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// v1 and v2 are known to have the same type.
|
||||||
|
func equalAny(v1, v2 reflect.Value) 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.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) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Ptr:
|
||||||
|
return equalAny(v1.Elem(), v2.Elem())
|
||||||
|
case reflect.Slice:
|
||||||
|
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
|
// short circuit: []byte
|
||||||
|
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)) {
|
||||||
|
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.
|
||||||
|
// em1 and em2 are extension maps.
|
||||||
|
func equalExtensions(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, m2 := e1.value, e2.value
|
||||||
|
|
||||||
|
if m1 != nil && m2 != nil {
|
||||||
|
// Both are unencoded.
|
||||||
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
||||||
|
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 {
|
||||||
|
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
191
Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go
generated
vendored
Normal file
191
Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package proto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
pb "./testdata"
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Four identical base messages.
|
||||||
|
// The init function adds extensions to some of them.
|
||||||
|
var messageWithoutExtension = &pb.MyMessage{Count: Int32(7)}
|
||||||
|
var messageWithExtension1a = &pb.MyMessage{Count: Int32(7)}
|
||||||
|
var messageWithExtension1b = &pb.MyMessage{Count: Int32(7)}
|
||||||
|
var messageWithExtension2 = &pb.MyMessage{Count: Int32(7)}
|
||||||
|
|
||||||
|
// Two messages with non-message extensions.
|
||||||
|
var messageWithInt32Extension1 = &pb.MyMessage{Count: Int32(8)}
|
||||||
|
var messageWithInt32Extension2 = &pb.MyMessage{Count: Int32(8)}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ext1 := &pb.Ext{Data: String("Kirk")}
|
||||||
|
ext2 := &pb.Ext{Data: String("Picard")}
|
||||||
|
|
||||||
|
// messageWithExtension1a has ext1, but never marshals it.
|
||||||
|
if err := SetExtension(messageWithExtension1a, pb.E_Ext_More, ext1); err != nil {
|
||||||
|
panic("SetExtension on 1a failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// messageWithExtension1b is the unmarshaled form of messageWithExtension1a.
|
||||||
|
if err := SetExtension(messageWithExtension1b, pb.E_Ext_More, ext1); err != nil {
|
||||||
|
panic("SetExtension on 1b failed: " + err.Error())
|
||||||
|
}
|
||||||
|
buf, err := Marshal(messageWithExtension1b)
|
||||||
|
if err != nil {
|
||||||
|
panic("Marshal of 1b failed: " + err.Error())
|
||||||
|
}
|
||||||
|
messageWithExtension1b.Reset()
|
||||||
|
if err := Unmarshal(buf, messageWithExtension1b); err != nil {
|
||||||
|
panic("Unmarshal of 1b failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// messageWithExtension2 has ext2.
|
||||||
|
if err := SetExtension(messageWithExtension2, pb.E_Ext_More, ext2); err != nil {
|
||||||
|
panic("SetExtension on 2 failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(23)); err != nil {
|
||||||
|
panic("SetExtension on Int32-1 failed: " + err.Error())
|
||||||
|
}
|
||||||
|
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(24)); err != nil {
|
||||||
|
panic("SetExtension on Int32-2 failed: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var EqualTests = []struct {
|
||||||
|
desc string
|
||||||
|
a, b Message
|
||||||
|
exp bool
|
||||||
|
}{
|
||||||
|
{"different types", &pb.GoEnum{}, &pb.GoTestField{}, false},
|
||||||
|
{"equal empty", &pb.GoEnum{}, &pb.GoEnum{}, true},
|
||||||
|
{"nil vs nil", nil, nil, true},
|
||||||
|
{"typed nil vs typed nil", (*pb.GoEnum)(nil), (*pb.GoEnum)(nil), true},
|
||||||
|
{"typed nil vs empty", (*pb.GoEnum)(nil), &pb.GoEnum{}, false},
|
||||||
|
{"different typed nil", (*pb.GoEnum)(nil), (*pb.GoTestField)(nil), false},
|
||||||
|
|
||||||
|
{"one set field, one unset field", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{}, false},
|
||||||
|
{"one set field zero, one unset field", &pb.GoTest{Param: Int32(0)}, &pb.GoTest{}, false},
|
||||||
|
{"different set fields", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("bar")}, false},
|
||||||
|
{"equal set", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("foo")}, true},
|
||||||
|
|
||||||
|
{"repeated, one set", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{}, false},
|
||||||
|
{"repeated, different length", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{F_Int32Repeated: []int32{2}}, false},
|
||||||
|
{"repeated, different value", &pb.GoTest{F_Int32Repeated: []int32{2}}, &pb.GoTest{F_Int32Repeated: []int32{3}}, false},
|
||||||
|
{"repeated, equal", &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, true},
|
||||||
|
{"repeated, nil equal nil", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: nil}, true},
|
||||||
|
{"repeated, nil equal empty", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: []int32{}}, true},
|
||||||
|
{"repeated, empty equal nil", &pb.GoTest{F_Int32Repeated: []int32{}}, &pb.GoTest{F_Int32Repeated: nil}, true},
|
||||||
|
|
||||||
|
{
|
||||||
|
"nested, different",
|
||||||
|
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("foo")}},
|
||||||
|
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("bar")}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nested, equal",
|
||||||
|
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
|
||||||
|
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{"bytes", &pb.OtherMessage{Value: []byte("foo")}, &pb.OtherMessage{Value: []byte("foo")}, true},
|
||||||
|
{"bytes, empty", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: []byte{}}, true},
|
||||||
|
{"bytes, empty vs nil", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: nil}, false},
|
||||||
|
{
|
||||||
|
"repeated bytes",
|
||||||
|
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
|
||||||
|
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{"extension vs. no extension", messageWithoutExtension, messageWithExtension1a, false},
|
||||||
|
{"extension vs. same extension", messageWithExtension1a, messageWithExtension1b, true},
|
||||||
|
{"extension vs. different extension", messageWithExtension1a, messageWithExtension2, false},
|
||||||
|
|
||||||
|
{"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true},
|
||||||
|
{"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false},
|
||||||
|
|
||||||
|
{
|
||||||
|
"message with group",
|
||||||
|
&pb.MyMessage{
|
||||||
|
Count: Int32(1),
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: Int32(5),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&pb.MyMessage{
|
||||||
|
Count: Int32(1),
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: Int32(5),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"map same",
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map different entry",
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{2: "Rob"}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map different key only",
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{2: "Ken"}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map different value only",
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob"}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEqual(t *testing.T) {
|
||||||
|
for _, tc := range EqualTests {
|
||||||
|
if res := Equal(tc.a, tc.b); res != tc.exp {
|
||||||
|
t.Errorf("%v: Equal(%v, %v) = %v, want %v", tc.desc, tc.a, tc.b, res, tc.exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
353
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go
generated
vendored
Normal file
353
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go
generated
vendored
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
// 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"
|
||||||
|
"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 that may be extended.
|
||||||
|
type extendableProto interface {
|
||||||
|
Message
|
||||||
|
ExtensionRangeArray() []ExtensionRange
|
||||||
|
ExtensionMap() map[int32]Extension
|
||||||
|
}
|
||||||
|
|
||||||
|
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 interface{}
|
||||||
|
enc []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRawExtension is for testing only.
|
||||||
|
func SetRawExtension(base extendableProto, id int32, b []byte) {
|
||||||
|
base.ExtensionMap()[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 {
|
||||||
|
// Check the extended type.
|
||||||
|
if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
|
||||||
|
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
|
||||||
|
func encodeExtensionMap(m map[int32]Extension) error {
|
||||||
|
for k, e := range m {
|
||||||
|
if e.value == nil || e.desc == nil {
|
||||||
|
// Extension is only in its encoded form.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't skip extensions that have an encoded form set,
|
||||||
|
// because the extension value may have been mutated after
|
||||||
|
// the last time this function was called.
|
||||||
|
|
||||||
|
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||||
|
props := extensionProperties(e.desc)
|
||||||
|
|
||||||
|
p := NewBuffer(nil)
|
||||||
|
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||||
|
// Pass a *T with a zero field and hope it all works out.
|
||||||
|
x := reflect.New(et)
|
||||||
|
x.Elem().Set(reflect.ValueOf(e.value))
|
||||||
|
if err := props.enc(p, props, toStructPointer(x)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.enc = p.buf
|
||||||
|
m[k] = e
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sizeExtensionMap(m map[int32]Extension) (n int) {
|
||||||
|
for _, e := range m {
|
||||||
|
if e.value == nil || e.desc == nil {
|
||||||
|
// Extension is only in its encoded form.
|
||||||
|
n += len(e.enc)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't skip extensions that have an encoded form set,
|
||||||
|
// because the extension value may have been mutated after
|
||||||
|
// the last time this function was called.
|
||||||
|
|
||||||
|
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||||
|
props := extensionProperties(e.desc)
|
||||||
|
|
||||||
|
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||||
|
// Pass a *T with a zero field and hope it all works out.
|
||||||
|
x := reflect.New(et)
|
||||||
|
x.Elem().Set(reflect.ValueOf(e.value))
|
||||||
|
n += props.size(props, toStructPointer(x))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasExtension returns whether the given extension is present in pb.
|
||||||
|
func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
|
||||||
|
// TODO: Check types, field numbers, etc.?
|
||||||
|
_, ok := pb.ExtensionMap()[extension.Field]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearExtension removes the given extension from pb.
|
||||||
|
func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
|
||||||
|
// TODO: Check types, field numbers, etc.?
|
||||||
|
delete(pb.ExtensionMap(), extension.Field)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExtension parses and returns the given extension of pb.
|
||||||
|
// If the extension is not present it returns ErrMissingExtension.
|
||||||
|
func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
if err := checkExtensionTypes(pb, extension); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
emap := pb.ExtensionMap()
|
||||||
|
e, ok := emap[extension.Field]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrMissingExtension
|
||||||
|
}
|
||||||
|
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 e.value, 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 = v
|
||||||
|
e.desc = extension
|
||||||
|
e.enc = nil
|
||||||
|
emap[extension.Field] = e
|
||||||
|
return e.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeExtension decodes an extension encoded in b.
|
||||||
|
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
o := NewBuffer(b)
|
||||||
|
|
||||||
|
t := reflect.TypeOf(extension.ExtensionType)
|
||||||
|
rep := extension.repeated()
|
||||||
|
|
||||||
|
props := extensionProperties(extension)
|
||||||
|
|
||||||
|
// t is a pointer to a struct, pointer to basic type or a slice.
|
||||||
|
// Allocate a "field" to store the pointer/slice itself; the
|
||||||
|
// pointer/slice will be stored here. We pass
|
||||||
|
// the address of this field to props.dec.
|
||||||
|
// This passes a zero field and a *t and lets props.dec
|
||||||
|
// interpret it as a *struct{ x t }.
|
||||||
|
value := reflect.New(t).Elem()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Discard wire type and field number varint. It isn't needed.
|
||||||
|
if _, err := o.DecodeVarint(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rep || o.index >= len(o.buf) {
|
||||||
|
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, ok := pb.(extendableProto)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("proto: not an extendable proto")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExtension sets the specified extension of pb to the specified value.
|
||||||
|
func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
|
||||||
|
if err := checkExtensionTypes(pb, extension); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
typ := reflect.TypeOf(extension.ExtensionType)
|
||||||
|
if typ != reflect.TypeOf(value) {
|
||||||
|
return errors.New("proto: bad extension value type")
|
||||||
|
}
|
||||||
|
|
||||||
|
pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()]
|
||||||
|
}
|
137
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go
generated
vendored
Normal file
137
Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2014 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
pb "./testdata"
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetExtensionsWithMissingExtensions(t *testing.T) {
|
||||||
|
msg := &pb.MyMessage{}
|
||||||
|
ext1 := &pb.Ext{}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil {
|
||||||
|
t.Fatalf("Could not set ext1: %s", ext1)
|
||||||
|
}
|
||||||
|
exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{
|
||||||
|
pb.E_Ext_More,
|
||||||
|
pb.E_Ext_Text,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetExtensions() failed: %s", err)
|
||||||
|
}
|
||||||
|
if exts[0] != ext1 {
|
||||||
|
t.Errorf("ext1 not in returned extensions: %T %v", exts[0], exts[0])
|
||||||
|
}
|
||||||
|
if exts[1] != nil {
|
||||||
|
t.Errorf("ext2 in returned extensions: %T %v", exts[1], exts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetExtensionStability(t *testing.T) {
|
||||||
|
check := func(m *pb.MyMessage) bool {
|
||||||
|
ext1, err := proto.GetExtension(m, pb.E_Ext_More)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetExtension() failed: %s", err)
|
||||||
|
}
|
||||||
|
ext2, err := proto.GetExtension(m, pb.E_Ext_More)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetExtension() failed: %s", err)
|
||||||
|
}
|
||||||
|
return ext1 == ext2
|
||||||
|
}
|
||||||
|
msg := &pb.MyMessage{Count: proto.Int32(4)}
|
||||||
|
ext0 := &pb.Ext{}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, ext0); err != nil {
|
||||||
|
t.Fatalf("Could not set ext1: %s", ext0)
|
||||||
|
}
|
||||||
|
if !check(msg) {
|
||||||
|
t.Errorf("GetExtension() not stable before marshaling")
|
||||||
|
}
|
||||||
|
bb, err := proto.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Marshal() failed: %s", err)
|
||||||
|
}
|
||||||
|
msg1 := &pb.MyMessage{}
|
||||||
|
err = proto.Unmarshal(bb, msg1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unmarshal() failed: %s", err)
|
||||||
|
}
|
||||||
|
if !check(msg1) {
|
||||||
|
t.Errorf("GetExtension() not stable after unmarshaling")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtensionsRoundTrip(t *testing.T) {
|
||||||
|
msg := &pb.MyMessage{}
|
||||||
|
ext1 := &pb.Ext{
|
||||||
|
Data: proto.String("hi"),
|
||||||
|
}
|
||||||
|
ext2 := &pb.Ext{
|
||||||
|
Data: proto.String("there"),
|
||||||
|
}
|
||||||
|
exists := proto.HasExtension(msg, pb.E_Ext_More)
|
||||||
|
if exists {
|
||||||
|
t.Error("Extension More present unexpectedly")
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, ext2); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
e, err := proto.GetExtension(msg, pb.E_Ext_More)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
x, ok := e.(*pb.Ext)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("e has type %T, expected testdata.Ext", e)
|
||||||
|
} else if *x.Data != "there" {
|
||||||
|
t.Errorf("SetExtension failed to overwrite, got %+v, not 'there'", x)
|
||||||
|
}
|
||||||
|
proto.ClearExtension(msg, pb.E_Ext_More)
|
||||||
|
if _, err = proto.GetExtension(msg, pb.E_Ext_More); err != proto.ErrMissingExtension {
|
||||||
|
t.Errorf("got %v, expected ErrMissingExtension", e)
|
||||||
|
}
|
||||||
|
if _, err := proto.GetExtension(msg, pb.E_X215); err == nil {
|
||||||
|
t.Error("expected bad extension error, got nil")
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_X215, 12); err == nil {
|
||||||
|
t.Error("expected extension err")
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, 12); err == nil {
|
||||||
|
t.Error("expected some sort of type mismatch error, got nil")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,759 @@
|
||||||
|
// 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.
|
||||||
|
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
func (m *Test) Reset() { *m = Test{} }
|
||||||
|
func (m *Test) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Test) ProtoMessage() {}
|
||||||
|
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 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),
|
||||||
|
Optionalgroup: &pb.Test_OptionalGroup{
|
||||||
|
RequiredField: proto.String("good bye"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
// etc.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is implemented by generated protocol buffer messages.
|
||||||
|
type Message interface {
|
||||||
|
Reset()
|
||||||
|
String() string
|
||||||
|
ProtoMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats records allocation details about the protocol buffer encoders
|
||||||
|
// and decoders. Useful for tuning the library itself.
|
||||||
|
type Stats struct {
|
||||||
|
Emalloc uint64 // mallocs in encode
|
||||||
|
Dmalloc uint64 // mallocs in decode
|
||||||
|
Encode uint64 // number of encodes
|
||||||
|
Decode uint64 // number of decodes
|
||||||
|
Chit uint64 // number of cache hits
|
||||||
|
Cmiss uint64 // number of cache misses
|
||||||
|
Size uint64 // number of sizes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set to true to enable stats collection.
|
||||||
|
const collectStats = false
|
||||||
|
|
||||||
|
var stats Stats
|
||||||
|
|
||||||
|
// GetStats returns a copy of the global Stats structure.
|
||||||
|
func GetStats() Stats { return stats }
|
||||||
|
|
||||||
|
// 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 // write point
|
||||||
|
|
||||||
|
// pools of basic types to amortize allocation.
|
||||||
|
bools []bool
|
||||||
|
uint32s []uint32
|
||||||
|
uint64s []uint64
|
||||||
|
|
||||||
|
// extra pools, only used with pointer_reflect.go
|
||||||
|
int32s []int32
|
||||||
|
int64s []int64
|
||||||
|
float32s []float32
|
||||||
|
float64s []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 (o *Buffer) DebugPrint(s string, b []byte) {
|
||||||
|
var u uint64
|
||||||
|
|
||||||
|
obuf := o.buf
|
||||||
|
index := o.index
|
||||||
|
o.buf = b
|
||||||
|
o.index = 0
|
||||||
|
depth := 0
|
||||||
|
|
||||||
|
fmt.Printf("\n--- %s ---\n", s)
|
||||||
|
|
||||||
|
out:
|
||||||
|
for {
|
||||||
|
for i := 0; i < depth; i++ {
|
||||||
|
fmt.Print(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
index := o.index
|
||||||
|
if index == len(o.buf) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
op, err := o.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 = o.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 = o.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 = o.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)
|
||||||
|
break
|
||||||
|
|
||||||
|
case WireVarint:
|
||||||
|
u, err = o.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:
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
||||||
|
depth++
|
||||||
|
|
||||||
|
case WireEndGroup:
|
||||||
|
depth--
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if depth != 0 {
|
||||||
|
fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
o.buf = obuf
|
||||||
|
o.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)
|
||||||
|
if f.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// f is *T or []*T
|
||||||
|
if f.Kind() == reflect.Ptr {
|
||||||
|
setDefaults(f, recur, zeros)
|
||||||
|
} else {
|
||||||
|
for i := 0; i < f.Len(); i++ {
|
||||||
|
e := f.Index(i)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToStruct(t reflect.Type) bool {
|
||||||
|
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// nested messages
|
||||||
|
if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
|
||||||
|
dm.nested = append(dm.nested, fi)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sf := scalarField{
|
||||||
|
index: fi,
|
||||||
|
kind: ft.Elem().Kind(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// scalar fields without defaults
|
||||||
|
if !prop.HasDefault {
|
||||||
|
dm.scalars = append(dm.scalars, sf)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// a scalar field: either *T or []byte
|
||||||
|
switch ft.Elem().Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
x, err := strconv.ParseBool(prop.Default)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default bool %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
case reflect.Float32:
|
||||||
|
x, err := strconv.ParseFloat(prop.Default, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = float32(x)
|
||||||
|
case reflect.Float64:
|
||||||
|
x, err := strconv.ParseFloat(prop.Default, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
case reflect.Int32:
|
||||||
|
x, err := strconv.ParseInt(prop.Default, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = int32(x)
|
||||||
|
case reflect.Int64:
|
||||||
|
x, err := strconv.ParseInt(prop.Default, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = uint32(x)
|
||||||
|
case reflect.Uint64:
|
||||||
|
x, err := strconv.ParseUint(prop.Default, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
default:
|
||||||
|
log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dm.scalars = append(dm.scalars, sf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map fields may have key types of non-float scalars, strings and enums.
|
||||||
|
// The easiest way to sort them in some deterministic order is to use fmt.
|
||||||
|
// If this turns out to be inefficient we can always consider other options,
|
||||||
|
// such as doing a Schwartzian transform.
|
||||||
|
|
||||||
|
type mapKeys []reflect.Value
|
||||||
|
|
||||||
|
func (s mapKeys) Len() int { return len(s) }
|
||||||
|
func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s mapKeys) Less(i, j int) bool {
|
||||||
|
return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
|
||||||
|
}
|
287
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go
generated
vendored
Normal file
287
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go
generated
vendored
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
// 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 (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// When a proto1 proto has a field that looks like:
|
||||||
|
// optional message<MessageSet> info = 3;
|
||||||
|
// the protocol compiler produces a field in the generated struct that looks like:
|
||||||
|
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
|
||||||
|
// The package is automatically inserted so there is no need for that proto file to
|
||||||
|
// import 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 {
|
||||||
|
if ms.find(pb) != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
|
||||||
|
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
||||||
|
if err := encodeExtensionMap(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort extension IDs to provide a deterministic encoding.
|
||||||
|
// See also enc_map in encode.go.
|
||||||
|
ids := make([]int, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, int(id))
|
||||||
|
}
|
||||||
|
sort.Ints(ids)
|
||||||
|
|
||||||
|
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||||
|
for _, id := range ids {
|
||||||
|
e := m[int32(id)]
|
||||||
|
// Remove the wire type and field number varint, as well as the length varint.
|
||||||
|
msg := skipVarint(skipVarint(e.enc))
|
||||||
|
|
||||||
|
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||||
|
TypeId: Int32(int32(id)),
|
||||||
|
Message: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Marshal(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||||
|
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
|
||||||
|
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteByte('{')
|
||||||
|
|
||||||
|
// Process the map in key order for deterministic output.
|
||||||
|
ids := make([]int32, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
|
||||||
|
|
||||||
|
for i, id := range ids {
|
||||||
|
ext := m[id]
|
||||||
|
if i > 0 {
|
||||||
|
b.WriteByte(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
msd, ok := messageSetMap[id]
|
||||||
|
if !ok {
|
||||||
|
// Unknown type; we can't render it, so skip it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, `"[%s]":`, msd.name)
|
||||||
|
|
||||||
|
x := ext.value
|
||||||
|
if x == nil {
|
||||||
|
x = reflect.New(msd.t.Elem()).Interface()
|
||||||
|
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d, err := json.Marshal(x)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.Write(d)
|
||||||
|
}
|
||||||
|
b.WriteByte('}')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
|
||||||
|
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error {
|
||||||
|
// Common-case fast path.
|
||||||
|
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is fairly tricky, and it's not clear that it is needed.
|
||||||
|
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A global registry of types that can be used in a MessageSet.
|
||||||
|
|
||||||
|
var messageSetMap = make(map[int32]messageSetDesc)
|
||||||
|
|
||||||
|
type messageSetDesc struct {
|
||||||
|
t reflect.Type // pointer to struct
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterMessageSetType is called from the generated code.
|
||||||
|
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
|
||||||
|
messageSetMap[fieldNum] = messageSetDesc{
|
||||||
|
t: reflect.TypeOf(m),
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
66
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go
generated
vendored
Normal file
66
Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2014 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 (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalMessageSetWithDuplicate(t *testing.T) {
|
||||||
|
// Check that a repeated message set entry will be concatenated.
|
||||||
|
in := &MessageSet{
|
||||||
|
Item: []*_MessageSet_Item{
|
||||||
|
{TypeId: Int32(12345), Message: []byte("hoo")},
|
||||||
|
{TypeId: Int32(12345), Message: []byte("hah")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b, err := Marshal(in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Marshal: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("Marshaled bytes: %q", b)
|
||||||
|
|
||||||
|
m := make(map[int32]Extension)
|
||||||
|
if err := UnmarshalMessageSet(b, m); err != nil {
|
||||||
|
t.Fatalf("UnmarshalMessageSet: %v", err)
|
||||||
|
}
|
||||||
|
ext, ok := m[12345]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Didn't retrieve extension 12345; map is %v", m)
|
||||||
|
}
|
||||||
|
// Skip wire type/field number and length varints.
|
||||||
|
got := skipVarint(skipVarint(ext.enc))
|
||||||
|
if want := []byte("hoohah"); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("Combined extension is %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
479
Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
479
Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
// 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 appengine
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A structPointer is a pointer to a struct.
|
||||||
|
type structPointer struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||||
|
// The reflect value must itself be a pointer to a struct.
|
||||||
|
func toStructPointer(v reflect.Value) structPointer {
|
||||||
|
return structPointer{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func structPointer_IsNil(p structPointer) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface returns the struct pointer as an interface value.
|
||||||
|
func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
|
||||||
|
return p.v.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A field identifies a field in a struct, accessible from a structPointer.
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// IsValid reports whether the field identifier is valid.
|
||||||
|
func (f field) IsValid() bool { return f != nil }
|
||||||
|
|
||||||
|
// field returns the given field in the struct as a reflect value.
|
||||||
|
func structPointer_field(p structPointer, f field) reflect.Value {
|
||||||
|
// Special case: an extension map entry with a value of type T
|
||||||
|
// passes a *T to the struct-handling code with a zero field,
|
||||||
|
// expecting that it will be treated as equivalent to *struct{ X T },
|
||||||
|
// which has the same memory layout. We have to handle that case
|
||||||
|
// specially, because reflect will panic if we call FieldByIndex on a
|
||||||
|
// non-struct.
|
||||||
|
if f == nil {
|
||||||
|
return p.v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.v.Elem().FieldByIndex(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ifield returns the given field in the struct as an interface value.
|
||||||
|
func structPointer_ifield(p structPointer, f field) interface{} {
|
||||||
|
return structPointer_field(p, f).Addr().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the address of a []byte field in the struct.
|
||||||
|
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||||
|
return structPointer_ifield(p, f).(*[]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||||
|
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||||
|
return structPointer_ifield(p, f).(*[][]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns the address of a *bool field in the struct.
|
||||||
|
func structPointer_Bool(p structPointer, f field) **bool {
|
||||||
|
return structPointer_ifield(p, f).(**bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns the address of a bool field in the struct.
|
||||||
|
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||||
|
return structPointer_ifield(p, f).(*bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice returns the address of a []bool field in the struct.
|
||||||
|
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||||
|
return structPointer_ifield(p, f).(*[]bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the address of a *string field in the struct.
|
||||||
|
func structPointer_String(p structPointer, f field) **string {
|
||||||
|
return structPointer_ifield(p, f).(**string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns the address of a string field in the struct.
|
||||||
|
func structPointer_StringVal(p structPointer, f field) *string {
|
||||||
|
return structPointer_ifield(p, f).(*string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns the address of a []string field in the struct.
|
||||||
|
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||||
|
return structPointer_ifield(p, f).(*[]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtMap returns the address of an extension map field in the struct.
|
||||||
|
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||||
|
return structPointer_ifield(p, f).(*map[int32]Extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map returns the reflect.Value for the address of a map field in the struct.
|
||||||
|
func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||||
|
return structPointer_field(p, f).Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStructPointer writes a *struct field in the struct.
|
||||||
|
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||||
|
structPointer_field(p, f).Set(q.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStructPointer reads a *struct field in the struct.
|
||||||
|
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||||
|
return structPointer{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructPointerSlice the address of a []*struct field in the struct.
|
||||||
|
func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
|
||||||
|
return structPointerSlice{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A structPointerSlice represents the address of a slice of pointers to structs
|
||||||
|
// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
|
||||||
|
type structPointerSlice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p structPointerSlice) Len() int { return p.v.Len() }
|
||||||
|
func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
|
||||||
|
func (p structPointerSlice) Append(q structPointer) {
|
||||||
|
p.v.Set(reflect.Append(p.v, q.v))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
int32Type = reflect.TypeOf(int32(0))
|
||||||
|
uint32Type = reflect.TypeOf(uint32(0))
|
||||||
|
float32Type = reflect.TypeOf(float32(0))
|
||||||
|
int64Type = reflect.TypeOf(int64(0))
|
||||||
|
uint64Type = reflect.TypeOf(uint64(0))
|
||||||
|
float64Type = reflect.TypeOf(float64(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
|
||||||
|
// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
|
||||||
|
type word32 struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func word32_IsNil(p word32) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets p to point at a newly allocated word with bits set to x.
|
||||||
|
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
switch t {
|
||||||
|
case int32Type:
|
||||||
|
if len(o.int32s) == 0 {
|
||||||
|
o.int32s = make([]int32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.int32s[0] = int32(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.int32s[0]))
|
||||||
|
o.int32s = o.int32s[1:]
|
||||||
|
return
|
||||||
|
case uint32Type:
|
||||||
|
if len(o.uint32s) == 0 {
|
||||||
|
o.uint32s = make([]uint32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.uint32s[0] = x
|
||||||
|
p.v.Set(reflect.ValueOf(&o.uint32s[0]))
|
||||||
|
o.uint32s = o.uint32s[1:]
|
||||||
|
return
|
||||||
|
case float32Type:
|
||||||
|
if len(o.float32s) == 0 {
|
||||||
|
o.float32s = make([]float32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.float32s[0] = math.Float32frombits(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.float32s[0]))
|
||||||
|
o.float32s = o.float32s[1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be enum
|
||||||
|
p.v.Set(reflect.New(t))
|
||||||
|
p.v.Elem().SetInt(int64(int32(x)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the bits pointed at by p, as a uint32.
|
||||||
|
func word32_Get(p word32) uint32 {
|
||||||
|
elem := p.v.Elem()
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32(p structPointer, f field) word32 {
|
||||||
|
return word32{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Val represents a field of type int32, uint32, float32, or enum.
|
||||||
|
// That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
|
||||||
|
type word32Val struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets *p to x.
|
||||||
|
func word32Val_Set(p word32Val, x uint32) {
|
||||||
|
switch p.v.Type() {
|
||||||
|
case int32Type:
|
||||||
|
p.v.SetInt(int64(x))
|
||||||
|
return
|
||||||
|
case uint32Type:
|
||||||
|
p.v.SetUint(uint64(x))
|
||||||
|
return
|
||||||
|
case float32Type:
|
||||||
|
p.v.SetFloat(float64(math.Float32frombits(x)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be enum
|
||||||
|
p.v.SetInt(int64(int32(x)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the bits pointed at by p, as a uint32.
|
||||||
|
func word32Val_Get(p word32Val) uint32 {
|
||||||
|
elem := p.v
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
|
||||||
|
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||||
|
return word32Val{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Slice is a slice of 32-bit values.
|
||||||
|
// That is, v.Type() is []int32, []uint32, []float32, or []enum.
|
||||||
|
type word32Slice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Append(x uint32) {
|
||||||
|
n, m := p.v.Len(), p.v.Cap()
|
||||||
|
if n < m {
|
||||||
|
p.v.SetLen(n + 1)
|
||||||
|
} else {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||||
|
}
|
||||||
|
elem := p.v.Index(n)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
elem.SetInt(int64(int32(x)))
|
||||||
|
case reflect.Uint32:
|
||||||
|
elem.SetUint(uint64(x))
|
||||||
|
case reflect.Float32:
|
||||||
|
elem.SetFloat(float64(math.Float32frombits(x)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Len() int {
|
||||||
|
return p.v.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Index(i int) uint32 {
|
||||||
|
elem := p.v.Index(i)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
|
||||||
|
func structPointer_Word32Slice(p structPointer, f field) word32Slice {
|
||||||
|
return word32Slice{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64 is like word32 but for 64-bit values.
|
||||||
|
type word64 struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
switch t {
|
||||||
|
case int64Type:
|
||||||
|
if len(o.int64s) == 0 {
|
||||||
|
o.int64s = make([]int64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.int64s[0] = int64(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.int64s[0]))
|
||||||
|
o.int64s = o.int64s[1:]
|
||||||
|
return
|
||||||
|
case uint64Type:
|
||||||
|
if len(o.uint64s) == 0 {
|
||||||
|
o.uint64s = make([]uint64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.uint64s[0] = x
|
||||||
|
p.v.Set(reflect.ValueOf(&o.uint64s[0]))
|
||||||
|
o.uint64s = o.uint64s[1:]
|
||||||
|
return
|
||||||
|
case float64Type:
|
||||||
|
if len(o.float64s) == 0 {
|
||||||
|
o.float64s = make([]float64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.float64s[0] = math.Float64frombits(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.float64s[0]))
|
||||||
|
o.float64s = o.float64s[1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_IsNil(p word64) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Get(p word64) uint64 {
|
||||||
|
elem := p.v.Elem()
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return elem.Uint()
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(elem.Float())
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64(p structPointer, f field) word64 {
|
||||||
|
return word64{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Val is like word32Val but for 64-bit values.
|
||||||
|
type word64Val struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||||
|
switch p.v.Type() {
|
||||||
|
case int64Type:
|
||||||
|
p.v.SetInt(int64(x))
|
||||||
|
return
|
||||||
|
case uint64Type:
|
||||||
|
p.v.SetUint(x)
|
||||||
|
return
|
||||||
|
case float64Type:
|
||||||
|
p.v.SetFloat(math.Float64frombits(x))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Get(p word64Val) uint64 {
|
||||||
|
elem := p.v
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return elem.Uint()
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(elem.Float())
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||||
|
return word64Val{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type word64Slice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Append(x uint64) {
|
||||||
|
n, m := p.v.Len(), p.v.Cap()
|
||||||
|
if n < m {
|
||||||
|
p.v.SetLen(n + 1)
|
||||||
|
} else {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||||
|
}
|
||||||
|
elem := p.v.Index(n)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
elem.SetInt(int64(int64(x)))
|
||||||
|
case reflect.Uint64:
|
||||||
|
elem.SetUint(uint64(x))
|
||||||
|
case reflect.Float64:
|
||||||
|
elem.SetFloat(float64(math.Float64frombits(x)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Len() int {
|
||||||
|
return p.v.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Index(i int) uint64 {
|
||||||
|
elem := p.v.Index(i)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return uint64(elem.Uint())
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(float64(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Slice(p structPointer, f field) word64Slice {
|
||||||
|
return word64Slice{structPointer_field(p, f)}
|
||||||
|
}
|
266
Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
266
Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
// 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 !appengine
|
||||||
|
|
||||||
|
// This file contains the implementation of the proto field accesses using package unsafe.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: These type_Foo functions would more idiomatically be methods,
|
||||||
|
// but Go does not allow methods on pointer types, and we must preserve
|
||||||
|
// some pointer type for the garbage collector. We use these
|
||||||
|
// funcs with clunky names as our poor approximation to methods.
|
||||||
|
//
|
||||||
|
// An alternative would be
|
||||||
|
// type structPointer struct { p unsafe.Pointer }
|
||||||
|
// but that does not registerize as well.
|
||||||
|
|
||||||
|
// A structPointer is a pointer to a struct.
|
||||||
|
type structPointer unsafe.Pointer
|
||||||
|
|
||||||
|
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||||
|
func toStructPointer(v reflect.Value) structPointer {
|
||||||
|
return structPointer(unsafe.Pointer(v.Pointer()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func structPointer_IsNil(p structPointer) bool {
|
||||||
|
return p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface returns the struct pointer, assumed to have element type t,
|
||||||
|
// as an interface value.
|
||||||
|
func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
|
||||||
|
return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A field identifies a field in a struct, accessible from a structPointer.
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// IsValid reports whether the field identifier is valid.
|
||||||
|
func (f field) IsValid() bool {
|
||||||
|
return f != ^field(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the address of a []byte field in the struct.
|
||||||
|
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||||
|
return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||||
|
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||||
|
return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns the address of a *bool field in the struct.
|
||||||
|
func structPointer_Bool(p structPointer, f field) **bool {
|
||||||
|
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns the address of a bool field in the struct.
|
||||||
|
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||||
|
return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice returns the address of a []bool field in the struct.
|
||||||
|
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||||
|
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the address of a *string field in the struct.
|
||||||
|
func structPointer_String(p structPointer, f field) **string {
|
||||||
|
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns the address of a string field in the struct.
|
||||||
|
func structPointer_StringVal(p structPointer, f field) *string {
|
||||||
|
return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns the address of a []string field in the struct.
|
||||||
|
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||||
|
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtMap returns the address of an extension map field in the struct.
|
||||||
|
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||||
|
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map returns the reflect.Value for the address of a map field in the struct.
|
||||||
|
func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||||
|
return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStructPointer writes a *struct field in the struct.
|
||||||
|
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||||
|
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStructPointer reads a *struct field in the struct.
|
||||||
|
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||||
|
return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructPointerSlice the address of a []*struct field in the struct.
|
||||||
|
func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
|
||||||
|
return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
|
||||||
|
type structPointerSlice []structPointer
|
||||||
|
|
||||||
|
func (v *structPointerSlice) Len() int { return len(*v) }
|
||||||
|
func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
|
||||||
|
func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
|
||||||
|
|
||||||
|
// A word32 is the address of a "pointer to 32-bit value" field.
|
||||||
|
type word32 **uint32
|
||||||
|
|
||||||
|
// IsNil reports whether *v is nil.
|
||||||
|
func word32_IsNil(p word32) bool {
|
||||||
|
return *p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets *v to point at a newly allocated word set to x.
|
||||||
|
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||||
|
if len(o.uint32s) == 0 {
|
||||||
|
o.uint32s = make([]uint32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.uint32s[0] = x
|
||||||
|
*p = &o.uint32s[0]
|
||||||
|
o.uint32s = o.uint32s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the value pointed at by *v.
|
||||||
|
func word32_Get(p word32) uint32 {
|
||||||
|
return **p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32(p structPointer, f field) word32 {
|
||||||
|
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Val is the address of a 32-bit value field.
|
||||||
|
type word32Val *uint32
|
||||||
|
|
||||||
|
// Set sets *p to x.
|
||||||
|
func word32Val_Set(p word32Val, x uint32) {
|
||||||
|
*p = x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the value pointed at by p.
|
||||||
|
func word32Val_Get(p word32Val) uint32 {
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||||
|
return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Slice is a slice of 32-bit values.
|
||||||
|
type word32Slice []uint32
|
||||||
|
|
||||||
|
func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
|
||||||
|
func (v *word32Slice) Len() int { return len(*v) }
|
||||||
|
func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
|
||||||
|
|
||||||
|
// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
|
||||||
|
func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
|
||||||
|
return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64 is like word32 but for 64-bit values.
|
||||||
|
type word64 **uint64
|
||||||
|
|
||||||
|
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||||
|
if len(o.uint64s) == 0 {
|
||||||
|
o.uint64s = make([]uint64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.uint64s[0] = x
|
||||||
|
*p = &o.uint64s[0]
|
||||||
|
o.uint64s = o.uint64s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_IsNil(p word64) bool {
|
||||||
|
return *p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Get(p word64) uint64 {
|
||||||
|
return **p
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64(p structPointer, f field) word64 {
|
||||||
|
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Val is like word32Val but for 64-bit values.
|
||||||
|
type word64Val *uint64
|
||||||
|
|
||||||
|
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||||
|
*p = x
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Get(p word64Val) uint64 {
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||||
|
return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Slice is like word32Slice but for 64-bit values.
|
||||||
|
type word64Slice []uint64
|
||||||
|
|
||||||
|
func (v *word64Slice) Append(x uint64) { *v = append(*v, x) }
|
||||||
|
func (v *word64Slice) Len() int { return len(*v) }
|
||||||
|
func (v *word64Slice) Index(i int) uint64 { return (*v)[i] }
|
||||||
|
|
||||||
|
func structPointer_Word64Slice(p structPointer, f field) *word64Slice {
|
||||||
|
return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
724
Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go
generated
vendored
Normal file
724
Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go
generated
vendored
Normal file
|
@ -0,0 +1,724 @@
|
||||||
|
// 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"
|
||||||
|
"os"
|
||||||
|
"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
|
||||||
|
)
|
||||||
|
|
||||||
|
const startSize = 10 // initial slice/string sizes
|
||||||
|
|
||||||
|
// Encoders are defined in encode.go
|
||||||
|
// An encoder outputs the full representation of a field, including its
|
||||||
|
// tag and encoder type.
|
||||||
|
type encoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||||
|
|
||||||
|
// A valueEncoder encodes a single integer in a particular encoding.
|
||||||
|
type valueEncoder func(o *Buffer, x uint64) error
|
||||||
|
|
||||||
|
// Sizers are defined in encode.go
|
||||||
|
// A sizer returns the encoded size of a field, including its tag and encoder
|
||||||
|
// type.
|
||||||
|
type sizer func(prop *Properties, base structPointer) int
|
||||||
|
|
||||||
|
// A valueSizer returns the encoded size of a single integer in a particular
|
||||||
|
// encoding.
|
||||||
|
type valueSizer func(x uint64) int
|
||||||
|
|
||||||
|
// Decoders are defined in decode.go
|
||||||
|
// A decoder creates a value from its wire representation.
|
||||||
|
// Unrecognized subelements are saved in unrec.
|
||||||
|
type decoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||||
|
|
||||||
|
// A valueDecoder decodes a single integer in a particular encoding.
|
||||||
|
type valueDecoder func(o *Buffer) (x uint64, err error)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
unrecField field // field id of the XXX_unrecognized []byte field
|
||||||
|
extendable bool // is this an extendable proto
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
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; set for []byte only
|
||||||
|
|
||||||
|
Default string // default value
|
||||||
|
HasDefault bool // whether an explicit default was provided
|
||||||
|
def_uint64 uint64
|
||||||
|
|
||||||
|
enc encoder
|
||||||
|
valEnc valueEncoder // set for bool and numeric types only
|
||||||
|
field field
|
||||||
|
tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
|
||||||
|
tagbuf [8]byte
|
||||||
|
stype reflect.Type // set for struct types only
|
||||||
|
sprop *StructProperties // set for struct types only
|
||||||
|
isMarshaler bool
|
||||||
|
isUnmarshaler bool
|
||||||
|
|
||||||
|
mtype reflect.Type // set for map types only
|
||||||
|
mkeyprop *Properties // set for map types only
|
||||||
|
mvalprop *Properties // set for map types only
|
||||||
|
|
||||||
|
size sizer
|
||||||
|
valSize valueSizer // set for bool and numeric types only
|
||||||
|
|
||||||
|
dec decoder
|
||||||
|
valDec valueDecoder // set for bool and numeric types only
|
||||||
|
|
||||||
|
// If this is a packable field, this will be the decoder for the packed version of the field.
|
||||||
|
packedDec decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
if p.OrigName != p.Name {
|
||||||
|
s += ",name=" + p.OrigName
|
||||||
|
}
|
||||||
|
if p.proto3 {
|
||||||
|
s += ",proto3"
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Wire = fields[0]
|
||||||
|
switch p.Wire {
|
||||||
|
case "varint":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeVarint
|
||||||
|
p.valDec = (*Buffer).DecodeVarint
|
||||||
|
p.valSize = sizeVarint
|
||||||
|
case "fixed32":
|
||||||
|
p.WireType = WireFixed32
|
||||||
|
p.valEnc = (*Buffer).EncodeFixed32
|
||||||
|
p.valDec = (*Buffer).DecodeFixed32
|
||||||
|
p.valSize = sizeFixed32
|
||||||
|
case "fixed64":
|
||||||
|
p.WireType = WireFixed64
|
||||||
|
p.valEnc = (*Buffer).EncodeFixed64
|
||||||
|
p.valDec = (*Buffer).DecodeFixed64
|
||||||
|
p.valSize = sizeFixed64
|
||||||
|
case "zigzag32":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeZigzag32
|
||||||
|
p.valDec = (*Buffer).DecodeZigzag32
|
||||||
|
p.valSize = sizeZigzag32
|
||||||
|
case "zigzag64":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeZigzag64
|
||||||
|
p.valDec = (*Buffer).DecodeZigzag64
|
||||||
|
p.valSize = sizeZigzag64
|
||||||
|
case "bytes", "group":
|
||||||
|
p.WireType = WireBytes
|
||||||
|
// no numeric converter for non-numeric types
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
p.Tag, err = strconv.Atoi(fields[1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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, "enum="):
|
||||||
|
p.Enum = f[5:]
|
||||||
|
case f == "proto3":
|
||||||
|
p.proto3 = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logNoSliceEnc(t1, t2 reflect.Type) {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
|
||||||
|
}
|
||||||
|
|
||||||
|
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
|
||||||
|
|
||||||
|
// Initialize the fields for encoding and decoding.
|
||||||
|
func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
|
||||||
|
p.enc = nil
|
||||||
|
p.dec = nil
|
||||||
|
p.size = nil
|
||||||
|
|
||||||
|
switch t1 := typ; t1.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
|
||||||
|
|
||||||
|
// proto3 scalar types
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
p.enc = (*Buffer).enc_proto3_bool
|
||||||
|
p.dec = (*Buffer).dec_proto3_bool
|
||||||
|
p.size = size_proto3_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int32
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32
|
||||||
|
p.size = size_proto3_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_uint32
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32 // can reuse
|
||||||
|
p.size = size_proto3_uint32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int64
|
||||||
|
p.dec = (*Buffer).dec_proto3_int64
|
||||||
|
p.size = size_proto3_int64
|
||||||
|
case reflect.Float32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32
|
||||||
|
p.size = size_proto3_uint32
|
||||||
|
case reflect.Float64:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_proto3_int64
|
||||||
|
p.size = size_proto3_int64
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_proto3_string
|
||||||
|
p.dec = (*Buffer).dec_proto3_string
|
||||||
|
p.size = size_proto3_string
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
switch t2 := t1.Elem(); t2.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
|
||||||
|
break
|
||||||
|
case reflect.Bool:
|
||||||
|
p.enc = (*Buffer).enc_bool
|
||||||
|
p.dec = (*Buffer).dec_bool
|
||||||
|
p.size = size_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
p.enc = (*Buffer).enc_int32
|
||||||
|
p.dec = (*Buffer).dec_int32
|
||||||
|
p.size = size_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
p.enc = (*Buffer).enc_uint32
|
||||||
|
p.dec = (*Buffer).dec_int32 // can reuse
|
||||||
|
p.size = size_uint32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
p.enc = (*Buffer).enc_int64
|
||||||
|
p.dec = (*Buffer).dec_int64
|
||||||
|
p.size = size_int64
|
||||||
|
case reflect.Float32:
|
||||||
|
p.enc = (*Buffer).enc_uint32 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_int32
|
||||||
|
p.size = size_uint32
|
||||||
|
case reflect.Float64:
|
||||||
|
p.enc = (*Buffer).enc_int64 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_int64
|
||||||
|
p.size = size_int64
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_string
|
||||||
|
p.dec = (*Buffer).dec_string
|
||||||
|
p.size = size_string
|
||||||
|
case reflect.Struct:
|
||||||
|
p.stype = t1.Elem()
|
||||||
|
p.isMarshaler = isMarshaler(t1)
|
||||||
|
p.isUnmarshaler = isUnmarshaler(t1)
|
||||||
|
if p.Wire == "bytes" {
|
||||||
|
p.enc = (*Buffer).enc_struct_message
|
||||||
|
p.dec = (*Buffer).dec_struct_message
|
||||||
|
p.size = size_struct_message
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_struct_group
|
||||||
|
p.dec = (*Buffer).dec_struct_group
|
||||||
|
p.size = size_struct_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
switch t2 := t1.Elem(); t2.Kind() {
|
||||||
|
default:
|
||||||
|
logNoSliceEnc(t1, t2)
|
||||||
|
break
|
||||||
|
case reflect.Bool:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_bool
|
||||||
|
p.size = size_slice_packed_bool
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_bool
|
||||||
|
p.size = size_slice_bool
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_bool
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int32
|
||||||
|
p.size = size_slice_packed_int32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int32
|
||||||
|
p.size = size_slice_int32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||||
|
p.size = size_slice_packed_uint32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_uint32
|
||||||
|
p.size = size_slice_uint32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int64
|
||||||
|
p.size = size_slice_packed_int64
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int64
|
||||||
|
p.size = size_slice_int64
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int64
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||||
|
case reflect.Uint8:
|
||||||
|
p.enc = (*Buffer).enc_slice_byte
|
||||||
|
p.dec = (*Buffer).dec_slice_byte
|
||||||
|
p.size = size_slice_byte
|
||||||
|
if p.proto3 {
|
||||||
|
p.enc = (*Buffer).enc_proto3_slice_byte
|
||||||
|
p.size = size_proto3_slice_byte
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
switch t2.Bits() {
|
||||||
|
case 32:
|
||||||
|
// can just treat them as bits
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||||
|
p.size = size_slice_packed_uint32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_uint32
|
||||||
|
p.size = size_slice_uint32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case 64:
|
||||||
|
// can just treat them as bits
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int64
|
||||||
|
p.size = size_slice_packed_int64
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int64
|
||||||
|
p.size = size_slice_int64
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int64
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||||
|
default:
|
||||||
|
logNoSliceEnc(t1, t2)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_slice_string
|
||||||
|
p.dec = (*Buffer).dec_slice_string
|
||||||
|
p.size = size_slice_string
|
||||||
|
case reflect.Ptr:
|
||||||
|
switch t3 := t2.Elem(); t3.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
|
||||||
|
break
|
||||||
|
case reflect.Struct:
|
||||||
|
p.stype = t2.Elem()
|
||||||
|
p.isMarshaler = isMarshaler(t2)
|
||||||
|
p.isUnmarshaler = isUnmarshaler(t2)
|
||||||
|
if p.Wire == "bytes" {
|
||||||
|
p.enc = (*Buffer).enc_slice_struct_message
|
||||||
|
p.dec = (*Buffer).dec_slice_struct_message
|
||||||
|
p.size = size_slice_struct_message
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_struct_group
|
||||||
|
p.dec = (*Buffer).dec_slice_struct_group
|
||||||
|
p.size = size_slice_struct_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
switch t2.Elem().Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
|
||||||
|
break
|
||||||
|
case reflect.Uint8:
|
||||||
|
p.enc = (*Buffer).enc_slice_slice_byte
|
||||||
|
p.dec = (*Buffer).dec_slice_slice_byte
|
||||||
|
p.size = size_slice_slice_byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
p.enc = (*Buffer).enc_new_map
|
||||||
|
p.dec = (*Buffer).dec_new_map
|
||||||
|
p.size = size_new_map
|
||||||
|
|
||||||
|
p.mtype = t1
|
||||||
|
p.mkeyprop = &Properties{}
|
||||||
|
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||||
|
p.mvalprop = &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.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// precalculate tag code
|
||||||
|
wire := p.WireType
|
||||||
|
if p.Packed {
|
||||||
|
wire = WireBytes
|
||||||
|
}
|
||||||
|
x := uint32(p.Tag)<<3 | uint32(wire)
|
||||||
|
i := 0
|
||||||
|
for i = 0; x > 127; i++ {
|
||||||
|
p.tagbuf[i] = 0x80 | uint8(x&0x7F)
|
||||||
|
x >>= 7
|
||||||
|
}
|
||||||
|
p.tagbuf[i] = uint8(x)
|
||||||
|
p.tagcode = p.tagbuf[0 : i+1]
|
||||||
|
|
||||||
|
if p.stype != nil {
|
||||||
|
if lockGetProp {
|
||||||
|
p.sprop = GetProperties(p.stype)
|
||||||
|
} else {
|
||||||
|
p.sprop = getPropertiesLocked(p.stype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||||
|
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
// isMarshaler reports whether type t implements Marshaler.
|
||||||
|
func isMarshaler(t reflect.Type) bool {
|
||||||
|
// We're checking for (likely) pointer-receiver methods
|
||||||
|
// so if t is not a pointer, something is very wrong.
|
||||||
|
// The calls above only invoke isMarshaler on pointer types.
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
panic("proto: misuse of isMarshaler")
|
||||||
|
}
|
||||||
|
return t.Implements(marshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isUnmarshaler reports whether type t implements Unmarshaler.
|
||||||
|
func isUnmarshaler(t reflect.Type) bool {
|
||||||
|
// We're checking for (likely) pointer-receiver methods
|
||||||
|
// so if t is not a pointer, something is very wrong.
|
||||||
|
// The calls above only invoke isUnmarshaler on pointer types.
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
panic("proto: misuse of isUnmarshaler")
|
||||||
|
}
|
||||||
|
return t.Implements(unmarshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 f != nil {
|
||||||
|
p.field = toField(f)
|
||||||
|
}
|
||||||
|
if tag == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Parse(tag)
|
||||||
|
p.setEncAndDec(typ, f, lockGetProp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mutex sync.Mutex
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
mutex.Lock()
|
||||||
|
sprop := getPropertiesLocked(t)
|
||||||
|
mutex.Unlock()
|
||||||
|
return sprop
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPropertiesLocked requires that mutex is held.
|
||||||
|
func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
|
if prop, ok := propertiesMap[t]; ok {
|
||||||
|
if collectStats {
|
||||||
|
stats.Chit++
|
||||||
|
}
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
if collectStats {
|
||||||
|
stats.Cmiss++
|
||||||
|
}
|
||||||
|
|
||||||
|
prop := new(StructProperties)
|
||||||
|
// in case of recursive protos, fill this in now.
|
||||||
|
propertiesMap[t] = prop
|
||||||
|
|
||||||
|
// build properties
|
||||||
|
prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
|
||||||
|
prop.unrecField = invalidField
|
||||||
|
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)
|
||||||
|
|
||||||
|
if f.Name == "XXX_extensions" { // special case
|
||||||
|
p.enc = (*Buffer).enc_map
|
||||||
|
p.dec = nil // not needed
|
||||||
|
p.size = size_map
|
||||||
|
}
|
||||||
|
if f.Name == "XXX_unrecognized" { // special case
|
||||||
|
prop.unrecField = toField(&f)
|
||||||
|
}
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
|
||||||
|
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-order prop.order.
|
||||||
|
sort.Sort(prop)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the Properties object for the x[0]'th field of the structure.
|
||||||
|
func propByIndex(t reflect.Type, x []int) *Properties {
|
||||||
|
if len(x) != 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
prop := GetProperties(t)
|
||||||
|
return prop.Prop[x[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the address and type of a pointer to a struct from an interface.
|
||||||
|
func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
|
||||||
|
if pb == nil {
|
||||||
|
err = ErrNil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// get the reflect type of the pointer to the struct.
|
||||||
|
t = reflect.TypeOf(pb)
|
||||||
|
// get the address of the struct.
|
||||||
|
value := reflect.ValueOf(pb)
|
||||||
|
b = toStructPointer(value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
44
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile
generated
vendored
Normal file
44
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
#
|
||||||
|
# Copyright 2014 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.
|
||||||
|
|
||||||
|
|
||||||
|
include ../../Make.protobuf
|
||||||
|
|
||||||
|
all: regenerate
|
||||||
|
|
||||||
|
regenerate:
|
||||||
|
rm -f proto3.pb.go
|
||||||
|
make proto3.pb.go
|
||||||
|
|
||||||
|
# The following rules are just aids to development. Not needed for typical testing.
|
||||||
|
|
||||||
|
diff: regenerate
|
||||||
|
git diff proto3.pb.go
|
58
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto
generated
vendored
Normal file
58
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package proto3_proto;
|
||||||
|
|
||||||
|
message Message {
|
||||||
|
enum Humour {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
PUNS = 1;
|
||||||
|
SLAPSTICK = 2;
|
||||||
|
BILL_BAILEY = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
string name = 1;
|
||||||
|
Humour hilarity = 2;
|
||||||
|
uint32 height_in_cm = 3;
|
||||||
|
bytes data = 4;
|
||||||
|
int64 result_count = 7;
|
||||||
|
bool true_scotsman = 8;
|
||||||
|
float score = 9;
|
||||||
|
|
||||||
|
repeated uint64 key = 5;
|
||||||
|
Nested nested = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Nested {
|
||||||
|
string bunny = 1;
|
||||||
|
}
|
93
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go
generated
vendored
Normal file
93
Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2014 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
pb "./proto3_proto"
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProto3ZeroValues(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
m proto.Message
|
||||||
|
}{
|
||||||
|
{"zero message", &pb.Message{}},
|
||||||
|
{"empty bytes field", &pb.Message{Data: []byte{}}},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
b, err := proto.Marshal(test.m)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: proto.Marshal: %v", test.desc, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(b) > 0 {
|
||||||
|
t.Errorf("%s: Encoding is non-empty: %q", test.desc, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundTripProto3(t *testing.T) {
|
||||||
|
m := &pb.Message{
|
||||||
|
Name: "David", // (2 | 1<<3): 0x0a 0x05 "David"
|
||||||
|
Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01
|
||||||
|
HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01
|
||||||
|
Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto"
|
||||||
|
ResultCount: 47, // (0 | 7<<3): 0x38 0x2f
|
||||||
|
TrueScotsman: true, // (0 | 8<<3): 0x40 0x01
|
||||||
|
Score: 8.1, // (5 | 9<<3): 0x4d <8.1>
|
||||||
|
|
||||||
|
Key: []uint64{1, 0xdeadbeef},
|
||||||
|
Nested: &pb.Nested{
|
||||||
|
Bunny: "Monty",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
t.Logf(" m: %v", m)
|
||||||
|
|
||||||
|
b, err := proto.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("proto.Marshal: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf(" b: %q", b)
|
||||||
|
|
||||||
|
m2 := new(pb.Message)
|
||||||
|
if err := proto.Unmarshal(b, m2); err != nil {
|
||||||
|
t.Fatalf("proto.Unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("m2: %v", m2)
|
||||||
|
|
||||||
|
if !proto.Equal(m, m2) {
|
||||||
|
t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2)
|
||||||
|
}
|
||||||
|
}
|
63
Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go
generated
vendored
Normal file
63
Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a separate file and package from size_test.go because that one uses
|
||||||
|
// generated messages and thus may not be in package proto without having a circular
|
||||||
|
// dependency, whereas this file tests unexported details of size.go.
|
||||||
|
|
||||||
|
func TestVarintSize(t *testing.T) {
|
||||||
|
// Check the edge cases carefully.
|
||||||
|
testCases := []struct {
|
||||||
|
n uint64
|
||||||
|
size int
|
||||||
|
}{
|
||||||
|
{0, 1},
|
||||||
|
{1, 1},
|
||||||
|
{127, 1},
|
||||||
|
{128, 2},
|
||||||
|
{16383, 2},
|
||||||
|
{16384, 3},
|
||||||
|
{1<<63 - 1, 9},
|
||||||
|
{1 << 63, 10},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
size := sizeVarint(tc.n)
|
||||||
|
if size != tc.size {
|
||||||
|
t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go
generated
vendored
Normal file
135
Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package proto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
proto3pb "./proto3_proto"
|
||||||
|
pb "./testdata"
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)}
|
||||||
|
|
||||||
|
// messageWithExtension2 is in equal_test.go.
|
||||||
|
var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil {
|
||||||
|
log.Panicf("SetExtension: %v", err)
|
||||||
|
}
|
||||||
|
if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil {
|
||||||
|
log.Panicf("SetExtension: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force messageWithExtension3 to have the extension encoded.
|
||||||
|
Marshal(messageWithExtension3)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var SizeTests = []struct {
|
||||||
|
desc string
|
||||||
|
pb Message
|
||||||
|
}{
|
||||||
|
{"empty", &pb.OtherMessage{}},
|
||||||
|
// Basic types.
|
||||||
|
{"bool", &pb.Defaults{F_Bool: Bool(true)}},
|
||||||
|
{"int32", &pb.Defaults{F_Int32: Int32(12)}},
|
||||||
|
{"negative int32", &pb.Defaults{F_Int32: Int32(-1)}},
|
||||||
|
{"small int64", &pb.Defaults{F_Int64: Int64(1)}},
|
||||||
|
{"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}},
|
||||||
|
{"negative int64", &pb.Defaults{F_Int64: Int64(-1)}},
|
||||||
|
{"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}},
|
||||||
|
{"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}},
|
||||||
|
{"uint32", &pb.Defaults{F_Uint32: Uint32(123)}},
|
||||||
|
{"uint64", &pb.Defaults{F_Uint64: Uint64(124)}},
|
||||||
|
{"float", &pb.Defaults{F_Float: Float32(12.6)}},
|
||||||
|
{"double", &pb.Defaults{F_Double: Float64(13.9)}},
|
||||||
|
{"string", &pb.Defaults{F_String: String("niles")}},
|
||||||
|
{"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}},
|
||||||
|
{"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}},
|
||||||
|
{"sint32", &pb.Defaults{F_Sint32: Int32(65)}},
|
||||||
|
{"sint64", &pb.Defaults{F_Sint64: Int64(67)}},
|
||||||
|
{"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}},
|
||||||
|
// Repeated.
|
||||||
|
{"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}},
|
||||||
|
{"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}},
|
||||||
|
{"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}},
|
||||||
|
{"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}},
|
||||||
|
{"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}},
|
||||||
|
{"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{
|
||||||
|
// Need enough large numbers to verify that the header is counting the number of bytes
|
||||||
|
// for the field, not the number of elements.
|
||||||
|
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
|
||||||
|
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
|
||||||
|
}}},
|
||||||
|
{"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}},
|
||||||
|
{"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}},
|
||||||
|
// Nested.
|
||||||
|
{"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}},
|
||||||
|
{"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}},
|
||||||
|
// Other things.
|
||||||
|
{"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}},
|
||||||
|
{"extension (unencoded)", messageWithExtension1},
|
||||||
|
{"extension (encoded)", messageWithExtension3},
|
||||||
|
// proto3 message
|
||||||
|
{"proto3 empty", &proto3pb.Message{}},
|
||||||
|
{"proto3 bool", &proto3pb.Message{TrueScotsman: true}},
|
||||||
|
{"proto3 int64", &proto3pb.Message{ResultCount: 1}},
|
||||||
|
{"proto3 uint32", &proto3pb.Message{HeightInCm: 123}},
|
||||||
|
{"proto3 float", &proto3pb.Message{Score: 12.6}},
|
||||||
|
{"proto3 string", &proto3pb.Message{Name: "Snezana"}},
|
||||||
|
{"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}},
|
||||||
|
{"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}},
|
||||||
|
{"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
|
||||||
|
|
||||||
|
{"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}},
|
||||||
|
{"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}},
|
||||||
|
{"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSize(t *testing.T) {
|
||||||
|
for _, tc := range SizeTests {
|
||||||
|
size := Size(tc.pb)
|
||||||
|
b, err := Marshal(tc.pb)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: Marshal failed: %v", tc.desc, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if size != len(b) {
|
||||||
|
t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b))
|
||||||
|
t.Logf("%v: bytes: %#v", tc.desc, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile
generated
vendored
Normal file
50
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
include ../../Make.protobuf
|
||||||
|
|
||||||
|
all: regenerate
|
||||||
|
|
||||||
|
regenerate:
|
||||||
|
rm -f test.pb.go
|
||||||
|
make test.pb.go
|
||||||
|
|
||||||
|
# The following rules are just aids to development. Not needed for typical testing.
|
||||||
|
|
||||||
|
diff: regenerate
|
||||||
|
git diff test.pb.go
|
||||||
|
|
||||||
|
restore:
|
||||||
|
cp test.pb.go.golden test.pb.go
|
||||||
|
|
||||||
|
preserve:
|
||||||
|
cp test.pb.go test.pb.go.golden
|
86
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go
generated
vendored
Normal file
86
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Verify that the compiler output for test.proto is unchanged.
|
||||||
|
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sum returns in string form (for easy comparison) the SHA-1 hash of the named file.
|
||||||
|
func sum(t *testing.T, name string) string {
|
||||||
|
data, err := ioutil.ReadFile(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("sum(%q): length is %d", name, len(data))
|
||||||
|
hash := sha1.New()
|
||||||
|
_, err = hash.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("% x", hash.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(t *testing.T, name string, args ...string) {
|
||||||
|
cmd := exec.Command(name, args...)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGolden(t *testing.T) {
|
||||||
|
// Compute the original checksum.
|
||||||
|
goldenSum := sum(t, "test.pb.go")
|
||||||
|
// Run the proto compiler.
|
||||||
|
run(t, "protoc", "--go_out="+os.TempDir(), "test.proto")
|
||||||
|
newFile := filepath.Join(os.TempDir(), "test.pb.go")
|
||||||
|
defer os.Remove(newFile)
|
||||||
|
// Compute the new checksum.
|
||||||
|
newSum := sum(t, newFile)
|
||||||
|
// Verify
|
||||||
|
if newSum != goldenSum {
|
||||||
|
run(t, "diff", "-u", "test.pb.go", newFile)
|
||||||
|
t.Fatal("Code generated by protoc-gen-go has changed; update test.pb.go")
|
||||||
|
}
|
||||||
|
}
|
2389
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go
generated
vendored
Normal file
2389
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
434
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto
generated
vendored
Normal file
434
Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto
generated
vendored
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// A feature-rich test file for the protocol compiler and libraries.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package test_proto;
|
||||||
|
|
||||||
|
enum FOO { FOO1 = 1; };
|
||||||
|
|
||||||
|
message GoEnum {
|
||||||
|
required FOO foo = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GoTestField {
|
||||||
|
required string Label = 1;
|
||||||
|
required string Type = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GoTest {
|
||||||
|
// An enum, for completeness.
|
||||||
|
enum KIND {
|
||||||
|
VOID = 0;
|
||||||
|
|
||||||
|
// Basic types
|
||||||
|
BOOL = 1;
|
||||||
|
BYTES = 2;
|
||||||
|
FINGERPRINT = 3;
|
||||||
|
FLOAT = 4;
|
||||||
|
INT = 5;
|
||||||
|
STRING = 6;
|
||||||
|
TIME = 7;
|
||||||
|
|
||||||
|
// Groupings
|
||||||
|
TUPLE = 8;
|
||||||
|
ARRAY = 9;
|
||||||
|
MAP = 10;
|
||||||
|
|
||||||
|
// Table types
|
||||||
|
TABLE = 11;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
FUNCTION = 12; // last tag
|
||||||
|
};
|
||||||
|
|
||||||
|
// Some typical parameters
|
||||||
|
required KIND Kind = 1;
|
||||||
|
optional string Table = 2;
|
||||||
|
optional int32 Param = 3;
|
||||||
|
|
||||||
|
// Required, repeated and optional foreign fields.
|
||||||
|
required GoTestField RequiredField = 4;
|
||||||
|
repeated GoTestField RepeatedField = 5;
|
||||||
|
optional GoTestField OptionalField = 6;
|
||||||
|
|
||||||
|
// Required fields of all basic types
|
||||||
|
required bool F_Bool_required = 10;
|
||||||
|
required int32 F_Int32_required = 11;
|
||||||
|
required int64 F_Int64_required = 12;
|
||||||
|
required fixed32 F_Fixed32_required = 13;
|
||||||
|
required fixed64 F_Fixed64_required = 14;
|
||||||
|
required uint32 F_Uint32_required = 15;
|
||||||
|
required uint64 F_Uint64_required = 16;
|
||||||
|
required float F_Float_required = 17;
|
||||||
|
required double F_Double_required = 18;
|
||||||
|
required string F_String_required = 19;
|
||||||
|
required bytes F_Bytes_required = 101;
|
||||||
|
required sint32 F_Sint32_required = 102;
|
||||||
|
required sint64 F_Sint64_required = 103;
|
||||||
|
|
||||||
|
// Repeated fields of all basic types
|
||||||
|
repeated bool F_Bool_repeated = 20;
|
||||||
|
repeated int32 F_Int32_repeated = 21;
|
||||||
|
repeated int64 F_Int64_repeated = 22;
|
||||||
|
repeated fixed32 F_Fixed32_repeated = 23;
|
||||||
|
repeated fixed64 F_Fixed64_repeated = 24;
|
||||||
|
repeated uint32 F_Uint32_repeated = 25;
|
||||||
|
repeated uint64 F_Uint64_repeated = 26;
|
||||||
|
repeated float F_Float_repeated = 27;
|
||||||
|
repeated double F_Double_repeated = 28;
|
||||||
|
repeated string F_String_repeated = 29;
|
||||||
|
repeated bytes F_Bytes_repeated = 201;
|
||||||
|
repeated sint32 F_Sint32_repeated = 202;
|
||||||
|
repeated sint64 F_Sint64_repeated = 203;
|
||||||
|
|
||||||
|
// Optional fields of all basic types
|
||||||
|
optional bool F_Bool_optional = 30;
|
||||||
|
optional int32 F_Int32_optional = 31;
|
||||||
|
optional int64 F_Int64_optional = 32;
|
||||||
|
optional fixed32 F_Fixed32_optional = 33;
|
||||||
|
optional fixed64 F_Fixed64_optional = 34;
|
||||||
|
optional uint32 F_Uint32_optional = 35;
|
||||||
|
optional uint64 F_Uint64_optional = 36;
|
||||||
|
optional float F_Float_optional = 37;
|
||||||
|
optional double F_Double_optional = 38;
|
||||||
|
optional string F_String_optional = 39;
|
||||||
|
optional bytes F_Bytes_optional = 301;
|
||||||
|
optional sint32 F_Sint32_optional = 302;
|
||||||
|
optional sint64 F_Sint64_optional = 303;
|
||||||
|
|
||||||
|
// Default-valued fields of all basic types
|
||||||
|
optional bool F_Bool_defaulted = 40 [default=true];
|
||||||
|
optional int32 F_Int32_defaulted = 41 [default=32];
|
||||||
|
optional int64 F_Int64_defaulted = 42 [default=64];
|
||||||
|
optional fixed32 F_Fixed32_defaulted = 43 [default=320];
|
||||||
|
optional fixed64 F_Fixed64_defaulted = 44 [default=640];
|
||||||
|
optional uint32 F_Uint32_defaulted = 45 [default=3200];
|
||||||
|
optional uint64 F_Uint64_defaulted = 46 [default=6400];
|
||||||
|
optional float F_Float_defaulted = 47 [default=314159.];
|
||||||
|
optional double F_Double_defaulted = 48 [default=271828.];
|
||||||
|
optional string F_String_defaulted = 49 [default="hello, \"world!\"\n"];
|
||||||
|
optional bytes F_Bytes_defaulted = 401 [default="Bignose"];
|
||||||
|
optional sint32 F_Sint32_defaulted = 402 [default = -32];
|
||||||
|
optional sint64 F_Sint64_defaulted = 403 [default = -64];
|
||||||
|
|
||||||
|
// Packed repeated fields (no string or bytes).
|
||||||
|
repeated bool F_Bool_repeated_packed = 50 [packed=true];
|
||||||
|
repeated int32 F_Int32_repeated_packed = 51 [packed=true];
|
||||||
|
repeated int64 F_Int64_repeated_packed = 52 [packed=true];
|
||||||
|
repeated fixed32 F_Fixed32_repeated_packed = 53 [packed=true];
|
||||||
|
repeated fixed64 F_Fixed64_repeated_packed = 54 [packed=true];
|
||||||
|
repeated uint32 F_Uint32_repeated_packed = 55 [packed=true];
|
||||||
|
repeated uint64 F_Uint64_repeated_packed = 56 [packed=true];
|
||||||
|
repeated float F_Float_repeated_packed = 57 [packed=true];
|
||||||
|
repeated double F_Double_repeated_packed = 58 [packed=true];
|
||||||
|
repeated sint32 F_Sint32_repeated_packed = 502 [packed=true];
|
||||||
|
repeated sint64 F_Sint64_repeated_packed = 503 [packed=true];
|
||||||
|
|
||||||
|
// Required, repeated, and optional groups.
|
||||||
|
required group RequiredGroup = 70 {
|
||||||
|
required string RequiredField = 71;
|
||||||
|
};
|
||||||
|
|
||||||
|
repeated group RepeatedGroup = 80 {
|
||||||
|
required string RequiredField = 81;
|
||||||
|
};
|
||||||
|
|
||||||
|
optional group OptionalGroup = 90 {
|
||||||
|
required string RequiredField = 91;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing skipping of unrecognized fields.
|
||||||
|
// Numbers are all big, larger than tag numbers in GoTestField,
|
||||||
|
// the message used in the corresponding test.
|
||||||
|
message GoSkipTest {
|
||||||
|
required int32 skip_int32 = 11;
|
||||||
|
required fixed32 skip_fixed32 = 12;
|
||||||
|
required fixed64 skip_fixed64 = 13;
|
||||||
|
required string skip_string = 14;
|
||||||
|
required group SkipGroup = 15 {
|
||||||
|
required int32 group_int32 = 16;
|
||||||
|
required string group_string = 17;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing packed/non-packed decoder switching.
|
||||||
|
// A serialized instance of one should be deserializable as the other.
|
||||||
|
message NonPackedTest {
|
||||||
|
repeated int32 a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PackedTest {
|
||||||
|
repeated int32 b = 1 [packed=true];
|
||||||
|
}
|
||||||
|
|
||||||
|
message MaxTag {
|
||||||
|
// Maximum possible tag number.
|
||||||
|
optional string last_field = 536870911;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OldMessage {
|
||||||
|
message Nested {
|
||||||
|
optional string name = 1;
|
||||||
|
}
|
||||||
|
optional Nested nested = 1;
|
||||||
|
|
||||||
|
optional int32 num = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMessage is wire compatible with OldMessage;
|
||||||
|
// imagine it as a future version.
|
||||||
|
message NewMessage {
|
||||||
|
message Nested {
|
||||||
|
optional string name = 1;
|
||||||
|
optional string food_group = 2;
|
||||||
|
}
|
||||||
|
optional Nested nested = 1;
|
||||||
|
|
||||||
|
// This is an int32 in OldMessage.
|
||||||
|
optional int64 num = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smaller tests for ASCII formatting.
|
||||||
|
|
||||||
|
message InnerMessage {
|
||||||
|
required string host = 1;
|
||||||
|
optional int32 port = 2 [default=4000];
|
||||||
|
optional bool connected = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OtherMessage {
|
||||||
|
optional int64 key = 1;
|
||||||
|
optional bytes value = 2;
|
||||||
|
optional float weight = 3;
|
||||||
|
optional InnerMessage inner = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MyMessage {
|
||||||
|
required int32 count = 1;
|
||||||
|
optional string name = 2;
|
||||||
|
optional string quote = 3;
|
||||||
|
repeated string pet = 4;
|
||||||
|
optional InnerMessage inner = 5;
|
||||||
|
repeated OtherMessage others = 6;
|
||||||
|
repeated InnerMessage rep_inner = 12;
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
RED = 0;
|
||||||
|
GREEN = 1;
|
||||||
|
BLUE = 2;
|
||||||
|
};
|
||||||
|
optional Color bikeshed = 7;
|
||||||
|
|
||||||
|
optional group SomeGroup = 8 {
|
||||||
|
optional int32 group_field = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This field becomes [][]byte in the generated code.
|
||||||
|
repeated bytes rep_bytes = 10;
|
||||||
|
|
||||||
|
optional double bigfloat = 11;
|
||||||
|
|
||||||
|
extensions 100 to max;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Ext {
|
||||||
|
extend MyMessage {
|
||||||
|
optional Ext more = 103;
|
||||||
|
optional string text = 104;
|
||||||
|
optional int32 number = 105;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional string data = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend MyMessage {
|
||||||
|
repeated string greeting = 106;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MyMessageSet {
|
||||||
|
option message_set_wire_format = true;
|
||||||
|
extensions 100 to max;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Empty {
|
||||||
|
}
|
||||||
|
|
||||||
|
extend MyMessageSet {
|
||||||
|
optional Empty x201 = 201;
|
||||||
|
optional Empty x202 = 202;
|
||||||
|
optional Empty x203 = 203;
|
||||||
|
optional Empty x204 = 204;
|
||||||
|
optional Empty x205 = 205;
|
||||||
|
optional Empty x206 = 206;
|
||||||
|
optional Empty x207 = 207;
|
||||||
|
optional Empty x208 = 208;
|
||||||
|
optional Empty x209 = 209;
|
||||||
|
optional Empty x210 = 210;
|
||||||
|
optional Empty x211 = 211;
|
||||||
|
optional Empty x212 = 212;
|
||||||
|
optional Empty x213 = 213;
|
||||||
|
optional Empty x214 = 214;
|
||||||
|
optional Empty x215 = 215;
|
||||||
|
optional Empty x216 = 216;
|
||||||
|
optional Empty x217 = 217;
|
||||||
|
optional Empty x218 = 218;
|
||||||
|
optional Empty x219 = 219;
|
||||||
|
optional Empty x220 = 220;
|
||||||
|
optional Empty x221 = 221;
|
||||||
|
optional Empty x222 = 222;
|
||||||
|
optional Empty x223 = 223;
|
||||||
|
optional Empty x224 = 224;
|
||||||
|
optional Empty x225 = 225;
|
||||||
|
optional Empty x226 = 226;
|
||||||
|
optional Empty x227 = 227;
|
||||||
|
optional Empty x228 = 228;
|
||||||
|
optional Empty x229 = 229;
|
||||||
|
optional Empty x230 = 230;
|
||||||
|
optional Empty x231 = 231;
|
||||||
|
optional Empty x232 = 232;
|
||||||
|
optional Empty x233 = 233;
|
||||||
|
optional Empty x234 = 234;
|
||||||
|
optional Empty x235 = 235;
|
||||||
|
optional Empty x236 = 236;
|
||||||
|
optional Empty x237 = 237;
|
||||||
|
optional Empty x238 = 238;
|
||||||
|
optional Empty x239 = 239;
|
||||||
|
optional Empty x240 = 240;
|
||||||
|
optional Empty x241 = 241;
|
||||||
|
optional Empty x242 = 242;
|
||||||
|
optional Empty x243 = 243;
|
||||||
|
optional Empty x244 = 244;
|
||||||
|
optional Empty x245 = 245;
|
||||||
|
optional Empty x246 = 246;
|
||||||
|
optional Empty x247 = 247;
|
||||||
|
optional Empty x248 = 248;
|
||||||
|
optional Empty x249 = 249;
|
||||||
|
optional Empty x250 = 250;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageList {
|
||||||
|
repeated group Message = 1 {
|
||||||
|
required string name = 2;
|
||||||
|
required int32 count = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Strings {
|
||||||
|
optional string string_field = 1;
|
||||||
|
optional bytes bytes_field = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Defaults {
|
||||||
|
enum Color {
|
||||||
|
RED = 0;
|
||||||
|
GREEN = 1;
|
||||||
|
BLUE = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default-valued fields of all basic types.
|
||||||
|
// Same as GoTest, but copied here to make testing easier.
|
||||||
|
optional bool F_Bool = 1 [default=true];
|
||||||
|
optional int32 F_Int32 = 2 [default=32];
|
||||||
|
optional int64 F_Int64 = 3 [default=64];
|
||||||
|
optional fixed32 F_Fixed32 = 4 [default=320];
|
||||||
|
optional fixed64 F_Fixed64 = 5 [default=640];
|
||||||
|
optional uint32 F_Uint32 = 6 [default=3200];
|
||||||
|
optional uint64 F_Uint64 = 7 [default=6400];
|
||||||
|
optional float F_Float = 8 [default=314159.];
|
||||||
|
optional double F_Double = 9 [default=271828.];
|
||||||
|
optional string F_String = 10 [default="hello, \"world!\"\n"];
|
||||||
|
optional bytes F_Bytes = 11 [default="Bignose"];
|
||||||
|
optional sint32 F_Sint32 = 12 [default=-32];
|
||||||
|
optional sint64 F_Sint64 = 13 [default=-64];
|
||||||
|
optional Color F_Enum = 14 [default=GREEN];
|
||||||
|
|
||||||
|
// More fields with crazy defaults.
|
||||||
|
optional float F_Pinf = 15 [default=inf];
|
||||||
|
optional float F_Ninf = 16 [default=-inf];
|
||||||
|
optional float F_Nan = 17 [default=nan];
|
||||||
|
|
||||||
|
// Sub-message.
|
||||||
|
optional SubDefaults sub = 18;
|
||||||
|
|
||||||
|
// Redundant but explicit defaults.
|
||||||
|
optional string str_zero = 19 [default=""];
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubDefaults {
|
||||||
|
optional int64 n = 1 [default=7];
|
||||||
|
}
|
||||||
|
|
||||||
|
message RepeatedEnum {
|
||||||
|
enum Color {
|
||||||
|
RED = 1;
|
||||||
|
}
|
||||||
|
repeated Color color = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MoreRepeated {
|
||||||
|
repeated bool bools = 1;
|
||||||
|
repeated bool bools_packed = 2 [packed=true];
|
||||||
|
repeated int32 ints = 3;
|
||||||
|
repeated int32 ints_packed = 4 [packed=true];
|
||||||
|
repeated int64 int64s_packed = 7 [packed=true];
|
||||||
|
repeated string strings = 5;
|
||||||
|
repeated fixed32 fixeds = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupOld and GroupNew have the same wire format.
|
||||||
|
// GroupNew has a new field inside a group.
|
||||||
|
|
||||||
|
message GroupOld {
|
||||||
|
optional group G = 101 {
|
||||||
|
optional int32 x = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupNew {
|
||||||
|
optional group G = 101 {
|
||||||
|
optional int32 x = 2;
|
||||||
|
optional int32 y = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message FloatingPoint {
|
||||||
|
required double f = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageWithMap {
|
||||||
|
map<int32, string> name_mapping = 1;
|
||||||
|
map<sint64, FloatingPoint> msg_mapping = 2;
|
||||||
|
map<bool, bytes> byte_mapping = 3;
|
||||||
|
}
|
|
@ -0,0 +1,789 @@
|
||||||
|
// 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"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
newline = []byte("\n")
|
||||||
|
spaces = []byte(" ")
|
||||||
|
gtNewline = []byte(">\n")
|
||||||
|
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.Printf("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
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
// raw is the interface satisfied by RawMessage.
|
||||||
|
type raw interface {
|
||||||
|
Bytes() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
|
if sv.Type() == messageSetType {
|
||||||
|
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 := 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() // TODO: should we sort these for deterministic output?
|
||||||
|
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 := writeAny(w, key, props.mkeyprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// value
|
||||||
|
if _, err := w.WriteString("value:"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := writeAny(w, val, props.mvalprop); 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
|
||||||
|
switch fv.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
if !fv.Bool() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case reflect.Int32, reflect.Int64:
|
||||||
|
if fv.Int() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case reflect.Uint32, reflect.Uint64:
|
||||||
|
if fv.Uint() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
if fv.Float() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if fv.String() == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeName(w, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if b, ok := fv.Interface().(raw); ok {
|
||||||
|
if err := writeRaw(w, b.Bytes()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums have a String method, so writeAny will work fine.
|
||||||
|
if err := 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 pv.Type().Implements(extendableProtoType) {
|
||||||
|
if err := writeExtensions(w, pv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeRaw writes an uninterpreted raw message.
|
||||||
|
func writeRaw(w *textWriter, b []byte) error {
|
||||||
|
if err := w.WriteByte('<'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
if err := writeUnknownStruct(w, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.unindent()
|
||||||
|
if err := w.WriteByte('>'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeAny writes an arbitrary field.
|
||||||
|
func 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.Interface().([]byte))); 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 tm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||||
|
text, err := tm.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = w.Write(text); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := 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 writeMessageSet(w *textWriter, ms *MessageSet) error {
|
||||||
|
for _, item := range ms.Item {
|
||||||
|
id := *item.TypeId
|
||||||
|
if msd, ok := messageSetMap[id]; ok {
|
||||||
|
// Known message set type.
|
||||||
|
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
|
||||||
|
pb := reflect.New(msd.t.Elem())
|
||||||
|
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
|
||||||
|
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := writeStruct(w, pb.Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unknown type.
|
||||||
|
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
if err := writeUnknownStruct(w, item.Message); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.unindent()
|
||||||
|
if _, err := w.Write(gtNewline); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||||
|
emap := extensionMaps[pv.Type().Elem()]
|
||||||
|
ep := pv.Interface().(extendableProto)
|
||||||
|
|
||||||
|
// Order the extensions by ID.
|
||||||
|
// This isn't strictly necessary, but it will give us
|
||||||
|
// canonical output, which will also make testing easier.
|
||||||
|
m := ep.ExtensionMap()
|
||||||
|
ids := make([]int32, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
sort.Sort(int32Slice(ids))
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeated extensions will appear as a slice.
|
||||||
|
if !desc.repeated() {
|
||||||
|
if err := writeExtension(w, desc.Name, pb); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v := reflect.ValueOf(pb)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func 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 := 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalText(w io.Writer, pb Message, compact bool) 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: compact,
|
||||||
|
}
|
||||||
|
|
||||||
|
if tm, ok := pb.(encoding.TextMarshaler); ok {
|
||||||
|
text, err := tm.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 := writeStruct(aw, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bw != nil {
|
||||||
|
return bw.Flush()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 marshalText(w, pb, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
||||||
|
func MarshalTextString(pb Message) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
marshalText(&buf, pb, false)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompactText writes a given protocol buffer in compact text format (one line).
|
||||||
|
func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
|
||||||
|
|
||||||
|
// CompactTextString is the same as CompactText, but returns the string directly.
|
||||||
|
func CompactTextString(pb Message) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
marshalText(&buf, pb, true)
|
||||||
|
return buf.String()
|
||||||
|
}
|
757
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
Normal file
757
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
Normal file
|
@ -0,0 +1,757 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 (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 %v", p.s[0:i+1])
|
||||||
|
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")
|
||||||
|
errBadHex = errors.New("proto: bad hexadecimal")
|
||||||
|
)
|
||||||
|
|
||||||
|
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', 'x', 'X':
|
||||||
|
if len(s) < 2 {
|
||||||
|
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
|
||||||
|
}
|
||||||
|
base := 8
|
||||||
|
ss := s[:2]
|
||||||
|
s = s[2:]
|
||||||
|
if r == 'x' || r == 'X' {
|
||||||
|
base = 16
|
||||||
|
} else {
|
||||||
|
ss = string(r) + ss
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseUint(ss, base, 8)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return string([]byte{byte(i)}), s, nil
|
||||||
|
case 'u', 'U':
|
||||||
|
n := 4
|
||||||
|
if r == 'U' {
|
||||||
|
n = 8
|
||||||
|
}
|
||||||
|
if len(s) < n {
|
||||||
|
return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := make([]byte, n/2)
|
||||||
|
for i := 0; i < n; i += 2 {
|
||||||
|
a, ok1 := unhex(s[i])
|
||||||
|
b, ok2 := unhex(s[i+1])
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
return "", "", errBadHex
|
||||||
|
}
|
||||||
|
bs[i/2] = a<<4 | b
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
return string(bs), s, nil
|
||||||
|
}
|
||||||
|
return "", "", fmt.Errorf(`unknown escape \%c`, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapted from src/pkg/strconv/quote.go.
|
||||||
|
func unhex(b byte) (v byte, ok bool) {
|
||||||
|
switch {
|
||||||
|
case '0' <= b && b <= '9':
|
||||||
|
return b - '0', true
|
||||||
|
case 'a' <= b && b <= 'f':
|
||||||
|
return b - 'a' + 10, true
|
||||||
|
case 'A' <= b && b <= 'F':
|
||||||
|
return b - 'A' + 10, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 && p.cur.value[0] == '"' {
|
||||||
|
// Look for multiple quoted strings separated by whitespace,
|
||||||
|
// and concatenate them.
|
||||||
|
cat := p.cur
|
||||||
|
for {
|
||||||
|
p.skipWhitespace()
|
||||||
|
if p.done || 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(st reflect.Type, name string) (int, *Properties, bool) {
|
||||||
|
sprops := GetProperties(st)
|
||||||
|
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()
|
||||||
|
reqCount := GetProperties(st).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]".
|
||||||
|
for {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == terminator {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tok.value == "[" {
|
||||||
|
// Looks like an extension.
|
||||||
|
//
|
||||||
|
// TODO: Check whether we need to handle
|
||||||
|
// namespace rooted names (e.g. ".something.Foo").
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
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 == tok.value {
|
||||||
|
desc = d
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if desc == nil {
|
||||||
|
return p.errorf("unrecognized extension %q", tok.value)
|
||||||
|
}
|
||||||
|
// Check the extension terminator.
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value != "]" {
|
||||||
|
return p.errorf("unrecognized extension terminator %q", tok.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
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().(extendableProto)
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is a normal, non-extension field.
|
||||||
|
name := tok.value
|
||||||
|
fi, props, ok := structFieldByName(st, name)
|
||||||
|
if !ok {
|
||||||
|
return p.errorf("unknown field name %q in %v", name, st)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := sv.Field(fi)
|
||||||
|
|
||||||
|
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 >
|
||||||
|
// Technically the "key" and "value" could come in any order,
|
||||||
|
// but in practice they won't.
|
||||||
|
|
||||||
|
tok := p.next()
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
if err := p.consumeToken("key"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken(":"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(key, props.mkeyprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken("value"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(val, props.mvalprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken(terminator); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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, st.Field(fi).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
|
||||||
|
} else if props.Required {
|
||||||
|
reqCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For backward compatibility, permit a semicolon or comma after a field.
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value != ";" && tok.value != "," {
|
||||||
|
p.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqCount > 0 {
|
||||||
|
return p.missingRequiredFieldError(sv)
|
||||||
|
}
|
||||||
|
return reqFieldErr
|
||||||
|
}
|
||||||
|
|
||||||
|
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. May already exist.
|
||||||
|
flen := fv.Len()
|
||||||
|
if flen == fv.Cap() {
|
||||||
|
nav := reflect.MakeSlice(at, flen, 2*flen+1)
|
||||||
|
reflect.Copy(nav, fv)
|
||||||
|
fv.Set(nav)
|
||||||
|
}
|
||||||
|
fv.SetLen(flen + 1)
|
||||||
|
|
||||||
|
// Read one.
|
||||||
|
p.back()
|
||||||
|
return p.readAny(fv.Index(flen), props)
|
||||||
|
case reflect.Bool:
|
||||||
|
// Either "true", "false", 1 or 0.
|
||||||
|
switch tok.value {
|
||||||
|
case "true", "1":
|
||||||
|
fv.SetBool(true)
|
||||||
|
return nil
|
||||||
|
case "false", "0":
|
||||||
|
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 {
|
||||||
|
err := um.UnmarshalText([]byte(s))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pb.Reset()
|
||||||
|
v := reflect.ValueOf(pb)
|
||||||
|
if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
511
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go
generated
vendored
Normal file
511
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go
generated
vendored
Normal file
|
@ -0,0 +1,511 @@
|
||||||
|
// 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
proto3pb "./proto3_proto"
|
||||||
|
. "./testdata"
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnmarshalTextTest struct {
|
||||||
|
in string
|
||||||
|
err string // if "", no error expected
|
||||||
|
out *MyMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildExtStructTest(text string) UnmarshalTextTest {
|
||||||
|
msg := &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
}
|
||||||
|
SetExtension(msg, E_Ext_More, &Ext{
|
||||||
|
Data: String("Hello, world!"),
|
||||||
|
})
|
||||||
|
return UnmarshalTextTest{in: text, out: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildExtDataTest(text string) UnmarshalTextTest {
|
||||||
|
msg := &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
}
|
||||||
|
SetExtension(msg, E_Ext_Text, String("Hello, world!"))
|
||||||
|
SetExtension(msg, E_Ext_Number, Int32(1729))
|
||||||
|
return UnmarshalTextTest{in: text, out: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildExtRepStringTest(text string) UnmarshalTextTest {
|
||||||
|
msg := &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
}
|
||||||
|
if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return UnmarshalTextTest{in: text, out: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unMarshalTextTests = []UnmarshalTextTest{
|
||||||
|
// Basic
|
||||||
|
{
|
||||||
|
in: " count:42\n name:\"Dave\" ",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("Dave"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Empty quoted string
|
||||||
|
{
|
||||||
|
in: `count:42 name:""`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String(""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string concatenation
|
||||||
|
{
|
||||||
|
in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("My name is elsewhere"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string with escaped apostrophe
|
||||||
|
{
|
||||||
|
in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("HOLIDAY - New Year's Day"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string with single quote
|
||||||
|
{
|
||||||
|
in: `count:42 name: 'Roger "The Ramster" Ramjet'`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String(`Roger "The Ramster" Ramjet`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string with all the accepted special characters from the C++ test
|
||||||
|
{
|
||||||
|
in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string with quoted backslash
|
||||||
|
{
|
||||||
|
in: `count:42 name: "\\'xyz"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String(`\'xyz`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string with UTF-8 bytes.
|
||||||
|
{
|
||||||
|
in: "count:42 name: '\303\277\302\201\xAB'",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("\303\277\302\201\xAB"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Bad quoted string
|
||||||
|
{
|
||||||
|
in: `inner: < host: "\0" >` + "\n",
|
||||||
|
err: `line 1.15: invalid quoted string "\0"`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number too large for int64
|
||||||
|
{
|
||||||
|
in: "count: 1 others { key: 123456789012345678901 }",
|
||||||
|
err: "line 1.23: invalid int64: 123456789012345678901",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number too large for int32
|
||||||
|
{
|
||||||
|
in: "count: 1234567890123",
|
||||||
|
err: "line 1.7: invalid int32: 1234567890123",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number in hexadecimal
|
||||||
|
{
|
||||||
|
in: "count: 0x2beef",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(0x2beef),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number in octal
|
||||||
|
{
|
||||||
|
in: "count: 024601",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(024601),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Floating point number with "f" suffix
|
||||||
|
{
|
||||||
|
in: "count: 4 others:< weight: 17.0f >",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(4),
|
||||||
|
Others: []*OtherMessage{
|
||||||
|
{
|
||||||
|
Weight: Float32(17),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Floating point positive infinity
|
||||||
|
{
|
||||||
|
in: "count: 4 bigfloat: inf",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(4),
|
||||||
|
Bigfloat: Float64(math.Inf(1)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Floating point negative infinity
|
||||||
|
{
|
||||||
|
in: "count: 4 bigfloat: -inf",
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(4),
|
||||||
|
Bigfloat: Float64(math.Inf(-1)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number too large for float32
|
||||||
|
{
|
||||||
|
in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
|
||||||
|
err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Number posing as a quoted string
|
||||||
|
{
|
||||||
|
in: `inner: < host: 12 >` + "\n",
|
||||||
|
err: `line 1.15: invalid string: 12`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string posing as int32
|
||||||
|
{
|
||||||
|
in: `count: "12"`,
|
||||||
|
err: `line 1.7: invalid int32: "12"`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted string posing a float32
|
||||||
|
{
|
||||||
|
in: `others:< weight: "17.4" >`,
|
||||||
|
err: `line 1.17: invalid float32: "17.4"`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Enum
|
||||||
|
{
|
||||||
|
in: `count:42 bikeshed: BLUE`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Bikeshed: MyMessage_BLUE.Enum(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Repeated field
|
||||||
|
{
|
||||||
|
in: `count:42 pet: "horsey" pet:"bunny"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Pet: []string{"horsey", "bunny"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Repeated message with/without colon and <>/{}
|
||||||
|
{
|
||||||
|
in: `count:42 others:{} others{} others:<> others:{}`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Others: []*OtherMessage{
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Missing colon for inner message
|
||||||
|
{
|
||||||
|
in: `count:42 inner < host: "cauchy.syd" >`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Inner: &InnerMessage{
|
||||||
|
Host: String("cauchy.syd"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Missing colon for string field
|
||||||
|
{
|
||||||
|
in: `name "Dave"`,
|
||||||
|
err: `line 1.5: expected ':', found "\"Dave\""`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Missing colon for int32 field
|
||||||
|
{
|
||||||
|
in: `count 42`,
|
||||||
|
err: `line 1.6: expected ':', found "42"`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Missing required field
|
||||||
|
{
|
||||||
|
in: `name: "Pawel"`,
|
||||||
|
err: `proto: required field "testdata.MyMessage.count" not set`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Name: String("Pawel"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Repeated non-repeated field
|
||||||
|
{
|
||||||
|
in: `name: "Rob" name: "Russ"`,
|
||||||
|
err: `line 1.12: non-repeated field "name" was repeated`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Group
|
||||||
|
{
|
||||||
|
in: `count: 17 SomeGroup { group_field: 12 }`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(17),
|
||||||
|
Somegroup: &MyMessage_SomeGroup{
|
||||||
|
GroupField: Int32(12),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Semicolon between fields
|
||||||
|
{
|
||||||
|
in: `count:3;name:"Calvin"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(3),
|
||||||
|
Name: String("Calvin"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Comma between fields
|
||||||
|
{
|
||||||
|
in: `count:4,name:"Ezekiel"`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(4),
|
||||||
|
Name: String("Ezekiel"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Extension
|
||||||
|
buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
|
||||||
|
buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
|
||||||
|
buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
|
||||||
|
buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
|
||||||
|
|
||||||
|
// Big all-in-one
|
||||||
|
{
|
||||||
|
in: "count:42 # Meaning\n" +
|
||||||
|
`name:"Dave" ` +
|
||||||
|
`quote:"\"I didn't want to go.\"" ` +
|
||||||
|
`pet:"bunny" ` +
|
||||||
|
`pet:"kitty" ` +
|
||||||
|
`pet:"horsey" ` +
|
||||||
|
`inner:<` +
|
||||||
|
` host:"footrest.syd" ` +
|
||||||
|
` port:7001 ` +
|
||||||
|
` connected:true ` +
|
||||||
|
`> ` +
|
||||||
|
`others:<` +
|
||||||
|
` key:3735928559 ` +
|
||||||
|
` value:"\x01A\a\f" ` +
|
||||||
|
`> ` +
|
||||||
|
`others:<` +
|
||||||
|
" weight:58.9 # Atomic weight of Co\n" +
|
||||||
|
` inner:<` +
|
||||||
|
` host:"lesha.mtv" ` +
|
||||||
|
` port:8002 ` +
|
||||||
|
` >` +
|
||||||
|
`>`,
|
||||||
|
out: &MyMessage{
|
||||||
|
Count: Int32(42),
|
||||||
|
Name: String("Dave"),
|
||||||
|
Quote: String(`"I didn't want to go."`),
|
||||||
|
Pet: []string{"bunny", "kitty", "horsey"},
|
||||||
|
Inner: &InnerMessage{
|
||||||
|
Host: String("footrest.syd"),
|
||||||
|
Port: Int32(7001),
|
||||||
|
Connected: Bool(true),
|
||||||
|
},
|
||||||
|
Others: []*OtherMessage{
|
||||||
|
{
|
||||||
|
Key: Int64(3735928559),
|
||||||
|
Value: []byte{0x1, 'A', '\a', '\f'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Weight: Float32(58.9),
|
||||||
|
Inner: &InnerMessage{
|
||||||
|
Host: String("lesha.mtv"),
|
||||||
|
Port: Int32(8002),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalText(t *testing.T) {
|
||||||
|
for i, test := range unMarshalTextTests {
|
||||||
|
pb := new(MyMessage)
|
||||||
|
err := UnmarshalText(test.in, pb)
|
||||||
|
if test.err == "" {
|
||||||
|
// We don't expect failure.
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test %d: Unexpected error: %v", i, err)
|
||||||
|
} else if !reflect.DeepEqual(pb, test.out) {
|
||||||
|
t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
|
||||||
|
i, pb, test.out)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We do expect failure.
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
|
||||||
|
} else if err.Error() != test.err {
|
||||||
|
t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
|
||||||
|
i, err.Error(), test.err)
|
||||||
|
} else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) {
|
||||||
|
t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
|
||||||
|
i, pb, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalTextCustomMessage(t *testing.T) {
|
||||||
|
msg := &textMessage{}
|
||||||
|
if err := UnmarshalText("custom", msg); err != nil {
|
||||||
|
t.Errorf("Unexpected error from custom unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if UnmarshalText("not custom", msg) == nil {
|
||||||
|
t.Errorf("Didn't get expected error from custom unmarshal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regression test; this caused a panic.
|
||||||
|
func TestRepeatedEnum(t *testing.T) {
|
||||||
|
pb := new(RepeatedEnum)
|
||||||
|
if err := UnmarshalText("color: RED", pb); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
exp := &RepeatedEnum{
|
||||||
|
Color: []RepeatedEnum_Color{RepeatedEnum_RED},
|
||||||
|
}
|
||||||
|
if !Equal(pb, exp) {
|
||||||
|
t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProto3TextParsing(t *testing.T) {
|
||||||
|
m := new(proto3pb.Message)
|
||||||
|
const in = `name: "Wallace" true_scotsman: true`
|
||||||
|
want := &proto3pb.Message{
|
||||||
|
Name: "Wallace",
|
||||||
|
TrueScotsman: true,
|
||||||
|
}
|
||||||
|
if err := UnmarshalText(in, m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !Equal(m, want) {
|
||||||
|
t.Errorf("\n got %v\nwant %v", m, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapParsing(t *testing.T) {
|
||||||
|
m := new(MessageWithMap)
|
||||||
|
const in = `name_mapping:<key:1234 value:"Feist"> name_mapping:<key:1 value:"Beatles">` +
|
||||||
|
`msg_mapping:<key:-4 value:<f: 2.0>>` +
|
||||||
|
`msg_mapping<key:-2 value<f: 4.0>>` + // no colon after "value"
|
||||||
|
`byte_mapping:<key:true value:"so be it">`
|
||||||
|
want := &MessageWithMap{
|
||||||
|
NameMapping: map[int32]string{
|
||||||
|
1: "Beatles",
|
||||||
|
1234: "Feist",
|
||||||
|
},
|
||||||
|
MsgMapping: map[int64]*FloatingPoint{
|
||||||
|
-4: {F: Float64(2.0)},
|
||||||
|
-2: {F: Float64(4.0)},
|
||||||
|
},
|
||||||
|
ByteMapping: map[bool][]byte{
|
||||||
|
true: []byte("so be it"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := UnmarshalText(in, m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !Equal(m, want) {
|
||||||
|
t.Errorf("\n got %v\nwant %v", m, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var benchInput string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
benchInput = "count: 4\n"
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
benchInput += "pet: \"fido\"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check it is valid input.
|
||||||
|
pb := new(MyMessage)
|
||||||
|
err := UnmarshalText(benchInput, pb)
|
||||||
|
if err != nil {
|
||||||
|
panic("Bad benchmark input: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalText(b *testing.B) {
|
||||||
|
pb := new(MyMessage)
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
UnmarshalText(benchInput, pb)
|
||||||
|
}
|
||||||
|
b.SetBytes(int64(len(benchInput)))
|
||||||
|
}
|
435
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go
generated
vendored
Normal file
435
Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go
generated
vendored
Normal file
|
@ -0,0 +1,435 @@
|
||||||
|
// 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
proto3pb "./proto3_proto"
|
||||||
|
pb "./testdata"
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// textMessage implements the methods that allow it to marshal and unmarshal
|
||||||
|
// itself as text.
|
||||||
|
type textMessage struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*textMessage) MarshalText() ([]byte, error) {
|
||||||
|
return []byte("custom"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*textMessage) UnmarshalText(bytes []byte) error {
|
||||||
|
if string(bytes) != "custom" {
|
||||||
|
return errors.New("expected 'custom'")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*textMessage) Reset() {}
|
||||||
|
func (*textMessage) String() string { return "" }
|
||||||
|
func (*textMessage) ProtoMessage() {}
|
||||||
|
|
||||||
|
func newTestMessage() *pb.MyMessage {
|
||||||
|
msg := &pb.MyMessage{
|
||||||
|
Count: proto.Int32(42),
|
||||||
|
Name: proto.String("Dave"),
|
||||||
|
Quote: proto.String(`"I didn't want to go."`),
|
||||||
|
Pet: []string{"bunny", "kitty", "horsey"},
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("footrest.syd"),
|
||||||
|
Port: proto.Int32(7001),
|
||||||
|
Connected: proto.Bool(true),
|
||||||
|
},
|
||||||
|
Others: []*pb.OtherMessage{
|
||||||
|
{
|
||||||
|
Key: proto.Int64(0xdeadbeef),
|
||||||
|
Value: []byte{1, 65, 7, 12},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Weight: proto.Float32(6.022),
|
||||||
|
Inner: &pb.InnerMessage{
|
||||||
|
Host: proto.String("lesha.mtv"),
|
||||||
|
Port: proto.Int32(8002),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bikeshed: pb.MyMessage_BLUE.Enum(),
|
||||||
|
Somegroup: &pb.MyMessage_SomeGroup{
|
||||||
|
GroupField: proto.Int32(8),
|
||||||
|
},
|
||||||
|
// One normally wouldn't do this.
|
||||||
|
// This is an undeclared tag 13, as a varint (wire type 0) with value 4.
|
||||||
|
XXX_unrecognized: []byte{13<<3 | 0, 4},
|
||||||
|
}
|
||||||
|
ext := &pb.Ext{
|
||||||
|
Data: proto.String("Big gobs for big rats"),
|
||||||
|
}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
greetings := []string{"adg", "easy", "cow"}
|
||||||
|
if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an unknown extension. We marshal a pb.Ext, and fake the ID.
|
||||||
|
b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...)
|
||||||
|
proto.SetRawExtension(msg, 201, b)
|
||||||
|
|
||||||
|
// Extensions can be plain fields, too, so let's test that.
|
||||||
|
b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19)
|
||||||
|
proto.SetRawExtension(msg, 202, b)
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = `count: 42
|
||||||
|
name: "Dave"
|
||||||
|
quote: "\"I didn't want to go.\""
|
||||||
|
pet: "bunny"
|
||||||
|
pet: "kitty"
|
||||||
|
pet: "horsey"
|
||||||
|
inner: <
|
||||||
|
host: "footrest.syd"
|
||||||
|
port: 7001
|
||||||
|
connected: true
|
||||||
|
>
|
||||||
|
others: <
|
||||||
|
key: 3735928559
|
||||||
|
value: "\001A\007\014"
|
||||||
|
>
|
||||||
|
others: <
|
||||||
|
weight: 6.022
|
||||||
|
inner: <
|
||||||
|
host: "lesha.mtv"
|
||||||
|
port: 8002
|
||||||
|
>
|
||||||
|
>
|
||||||
|
bikeshed: BLUE
|
||||||
|
SomeGroup {
|
||||||
|
group_field: 8
|
||||||
|
}
|
||||||
|
/* 2 unknown bytes */
|
||||||
|
13: 4
|
||||||
|
[testdata.Ext.more]: <
|
||||||
|
data: "Big gobs for big rats"
|
||||||
|
>
|
||||||
|
[testdata.greeting]: "adg"
|
||||||
|
[testdata.greeting]: "easy"
|
||||||
|
[testdata.greeting]: "cow"
|
||||||
|
/* 13 unknown bytes */
|
||||||
|
201: "\t3G skiing"
|
||||||
|
/* 3 unknown bytes */
|
||||||
|
202: 19
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestMarshalText(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := proto.MarshalText(buf, newTestMessage()); err != nil {
|
||||||
|
t.Fatalf("proto.MarshalText: %v", err)
|
||||||
|
}
|
||||||
|
s := buf.String()
|
||||||
|
if s != text {
|
||||||
|
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalTextCustomMessage(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := proto.MarshalText(buf, &textMessage{}); err != nil {
|
||||||
|
t.Fatalf("proto.MarshalText: %v", err)
|
||||||
|
}
|
||||||
|
s := buf.String()
|
||||||
|
if s != "custom" {
|
||||||
|
t.Errorf("Got %q, expected %q", s, "custom")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestMarshalTextNil(t *testing.T) {
|
||||||
|
want := "<nil>"
|
||||||
|
tests := []proto.Message{nil, (*pb.MyMessage)(nil)}
|
||||||
|
for i, test := range tests {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := proto.MarshalText(buf, test); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := buf.String(); got != want {
|
||||||
|
t.Errorf("%d: got %q want %q", i, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalTextUnknownEnum(t *testing.T) {
|
||||||
|
// The Color enum only specifies values 0-2.
|
||||||
|
m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()}
|
||||||
|
got := m.String()
|
||||||
|
const want = `bikeshed:3 `
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("\n got %q\nwant %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalTextBuffered(b *testing.B) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
m := newTestMessage()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buf.Reset()
|
||||||
|
proto.MarshalText(buf, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalTextUnbuffered(b *testing.B) {
|
||||||
|
w := ioutil.Discard
|
||||||
|
m := newTestMessage()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
proto.MarshalText(w, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compact(src string) string {
|
||||||
|
// s/[ \n]+/ /g; s/ $//;
|
||||||
|
dst := make([]byte, len(src))
|
||||||
|
space, comment := false, false
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if strings.HasPrefix(src[i:], "/*") {
|
||||||
|
comment = true
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if comment && strings.HasPrefix(src[i:], "*/") {
|
||||||
|
comment = false
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if comment {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c := src[i]
|
||||||
|
if c == ' ' || c == '\n' {
|
||||||
|
space = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') {
|
||||||
|
space = false
|
||||||
|
}
|
||||||
|
if c == '{' {
|
||||||
|
space = false
|
||||||
|
}
|
||||||
|
if space {
|
||||||
|
dst[j] = ' '
|
||||||
|
j++
|
||||||
|
space = false
|
||||||
|
}
|
||||||
|
dst[j] = c
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if space {
|
||||||
|
dst[j] = ' '
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return string(dst[0:j])
|
||||||
|
}
|
||||||
|
|
||||||
|
var compactText = compact(text)
|
||||||
|
|
||||||
|
func TestCompactText(t *testing.T) {
|
||||||
|
s := proto.CompactTextString(newTestMessage())
|
||||||
|
if s != compactText {
|
||||||
|
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringEscaping(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
in *pb.Strings
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// Test data from C++ test (TextFormatTest.StringEscape).
|
||||||
|
// Single divergence: we don't escape apostrophes.
|
||||||
|
&pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")},
|
||||||
|
"string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Test data from the same C++ test.
|
||||||
|
&pb.Strings{StringField: proto.String("\350\260\267\346\255\214")},
|
||||||
|
"string_field: \"\\350\\260\\267\\346\\255\\214\"\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Some UTF-8.
|
||||||
|
&pb.Strings{StringField: proto.String("\x00\x01\xff\x81")},
|
||||||
|
`string_field: "\000\001\377\201"` + "\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := proto.MarshalText(&buf, tc.in); err != nil {
|
||||||
|
t.Errorf("proto.MarsalText: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := buf.String()
|
||||||
|
if s != tc.out {
|
||||||
|
t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check round-trip.
|
||||||
|
pb := new(pb.Strings)
|
||||||
|
if err := proto.UnmarshalText(s, pb); err != nil {
|
||||||
|
t.Errorf("#%d: UnmarshalText: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !proto.Equal(pb, tc.in) {
|
||||||
|
t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A limitedWriter accepts some output before it fails.
|
||||||
|
// This is a proxy for something like a nearly-full or imminently-failing disk,
|
||||||
|
// or a network connection that is about to die.
|
||||||
|
type limitedWriter struct {
|
||||||
|
b bytes.Buffer
|
||||||
|
limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
var outOfSpace = errors.New("proto: insufficient space")
|
||||||
|
|
||||||
|
func (w *limitedWriter) Write(p []byte) (n int, err error) {
|
||||||
|
var avail = w.limit - w.b.Len()
|
||||||
|
if avail <= 0 {
|
||||||
|
return 0, outOfSpace
|
||||||
|
}
|
||||||
|
if len(p) <= avail {
|
||||||
|
return w.b.Write(p)
|
||||||
|
}
|
||||||
|
n, _ = w.b.Write(p[:avail])
|
||||||
|
return n, outOfSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalTextFailing(t *testing.T) {
|
||||||
|
// Try lots of different sizes to exercise more error code-paths.
|
||||||
|
for lim := 0; lim < len(text); lim++ {
|
||||||
|
buf := new(limitedWriter)
|
||||||
|
buf.limit = lim
|
||||||
|
err := proto.MarshalText(buf, newTestMessage())
|
||||||
|
// We expect a certain error, but also some partial results in the buffer.
|
||||||
|
if err != outOfSpace {
|
||||||
|
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace)
|
||||||
|
}
|
||||||
|
s := buf.b.String()
|
||||||
|
x := text[:buf.limit]
|
||||||
|
if s != x {
|
||||||
|
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloats(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
f float64
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{0, "0"},
|
||||||
|
{4.7, "4.7"},
|
||||||
|
{math.Inf(1), "inf"},
|
||||||
|
{math.Inf(-1), "-inf"},
|
||||||
|
{math.NaN(), "nan"},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
msg := &pb.FloatingPoint{F: &test.f}
|
||||||
|
got := strings.TrimSpace(msg.String())
|
||||||
|
want := `f:` + test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("f=%f: got %q, want %q", test.f, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepeatedNilText(t *testing.T) {
|
||||||
|
m := &pb.MessageList{
|
||||||
|
Message: []*pb.MessageList_Message{
|
||||||
|
nil,
|
||||||
|
&pb.MessageList_Message{
|
||||||
|
Name: proto.String("Horse"),
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
want := `Message <nil>
|
||||||
|
Message {
|
||||||
|
name: "Horse"
|
||||||
|
}
|
||||||
|
Message <nil>
|
||||||
|
`
|
||||||
|
if s := proto.MarshalTextString(m); s != want {
|
||||||
|
t.Errorf(" got: %s\nwant: %s", s, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProto3Text(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
m proto.Message
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
// zero message
|
||||||
|
{&proto3pb.Message{}, ``},
|
||||||
|
// zero message except for an empty byte slice
|
||||||
|
{&proto3pb.Message{Data: []byte{}}, ``},
|
||||||
|
// trivial case
|
||||||
|
{&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`},
|
||||||
|
// empty map
|
||||||
|
{&pb.MessageWithMap{}, ``},
|
||||||
|
// non-empty map; current map format is the same as a repeated struct
|
||||||
|
{
|
||||||
|
&pb.MessageWithMap{NameMapping: map[int32]string{1234: "Feist"}},
|
||||||
|
`name_mapping:<key:1234 value:"Feist" >`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
got := strings.TrimSpace(test.m.String())
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf("\n got %s\nwant %s", got, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
355
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/all_test.go
generated
vendored
Normal file
355
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/all_test.go
generated
vendored
Normal file
|
@ -0,0 +1,355 @@
|
||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"testing/quick"
|
||||||
|
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWriteDelimited(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
msg Message
|
||||||
|
buf []byte
|
||||||
|
n int
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
msg: &Empty{},
|
||||||
|
n: 1,
|
||||||
|
buf: []byte{0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
|
||||||
|
n: 3,
|
||||||
|
buf: []byte{2, 8, 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
msg: &Strings{
|
||||||
|
StringField: String(`This is my gigantic, unhappy string. It exceeds
|
||||||
|
the encoding size of a single byte varint. We are using it to fuzz test the
|
||||||
|
correctness of the header decoding mechanisms, which may prove problematic.
|
||||||
|
I expect it may. Let's hope you enjoy testing as much as we do.`),
|
||||||
|
},
|
||||||
|
n: 271,
|
||||||
|
buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109,
|
||||||
|
121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104,
|
||||||
|
97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73,
|
||||||
|
116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101,
|
||||||
|
110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102,
|
||||||
|
32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32,
|
||||||
|
118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32,
|
||||||
|
117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122,
|
||||||
|
122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114,
|
||||||
|
101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32,
|
||||||
|
104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103,
|
||||||
|
32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104,
|
||||||
|
105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112,
|
||||||
|
114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120,
|
||||||
|
112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101,
|
||||||
|
116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110,
|
||||||
|
106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32,
|
||||||
|
109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if n, err := WriteDelimited(&buf, test.msg); n != test.n || err != test.err {
|
||||||
|
t.Fatalf("WriteDelimited(buf, %#v) = %v, %v; want %v, %v", test.msg, n, err, test.n, test.err)
|
||||||
|
}
|
||||||
|
if out := buf.Bytes(); !bytes.Equal(out, test.buf) {
|
||||||
|
t.Fatalf("WriteDelimited(buf, %#v); buf = %v; want %v", test.msg, out, test.buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDelimited(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
buf []byte
|
||||||
|
msg Message
|
||||||
|
n int
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
buf: []byte{0},
|
||||||
|
msg: &Empty{},
|
||||||
|
n: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 3,
|
||||||
|
buf: []byte{2, 8, 1},
|
||||||
|
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109,
|
||||||
|
121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104,
|
||||||
|
97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73,
|
||||||
|
116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101,
|
||||||
|
110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102,
|
||||||
|
32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32,
|
||||||
|
118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32,
|
||||||
|
117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122,
|
||||||
|
122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114,
|
||||||
|
101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32,
|
||||||
|
104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103,
|
||||||
|
32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104,
|
||||||
|
105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112,
|
||||||
|
114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120,
|
||||||
|
112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101,
|
||||||
|
116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110,
|
||||||
|
106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32,
|
||||||
|
109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46},
|
||||||
|
msg: &Strings{
|
||||||
|
StringField: String(`This is my gigantic, unhappy string. It exceeds
|
||||||
|
the encoding size of a single byte varint. We are using it to fuzz test the
|
||||||
|
correctness of the header decoding mechanisms, which may prove problematic.
|
||||||
|
I expect it may. Let's hope you enjoy testing as much as we do.`),
|
||||||
|
},
|
||||||
|
n: 271,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
msg := Clone(test.msg)
|
||||||
|
msg.Reset()
|
||||||
|
if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); n != test.n || err != test.err {
|
||||||
|
t.Fatalf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err)
|
||||||
|
}
|
||||||
|
if !Equal(msg, test.msg) {
|
||||||
|
t.Fatalf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEndToEndValid(t *testing.T) {
|
||||||
|
for _, test := range [][]Message{
|
||||||
|
[]Message{&Empty{}},
|
||||||
|
[]Message{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
|
||||||
|
[]Message{&GoEnum{Foo: FOO_FOO1.Enum()}},
|
||||||
|
[]Message{&Strings{
|
||||||
|
StringField: String(`This is my gigantic, unhappy string. It exceeds
|
||||||
|
the encoding size of a single byte varint. We are using it to fuzz test the
|
||||||
|
correctness of the header decoding mechanisms, which may prove problematic.
|
||||||
|
I expect it may. Let's hope you enjoy testing as much as we do.`),
|
||||||
|
}},
|
||||||
|
} {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var written int
|
||||||
|
for i, msg := range test {
|
||||||
|
n, err := WriteDelimited(&buf, msg)
|
||||||
|
if err != nil {
|
||||||
|
// Assumption: TestReadDelimited and TestWriteDelimited are sufficient
|
||||||
|
// and inputs for this test are explicitly exercised there.
|
||||||
|
t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", test, i, err)
|
||||||
|
}
|
||||||
|
written += n
|
||||||
|
}
|
||||||
|
var read int
|
||||||
|
for i, msg := range test {
|
||||||
|
out := Clone(msg)
|
||||||
|
out.Reset()
|
||||||
|
n, _ := ReadDelimited(&buf, out)
|
||||||
|
// Decide to do EOF checking?
|
||||||
|
read += n
|
||||||
|
if !Equal(out, msg) {
|
||||||
|
t.Fatalf("out = %v; want %v[%d] = %#v", out, test, i, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if read != written {
|
||||||
|
t.Fatalf("%v read = %d; want %d", test, read, written)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// visitMessage empties the private state fields of the quick.Value()-generated
|
||||||
|
// Protocol Buffer messages, for they cause an inordinate amount of problems.
|
||||||
|
// This is because we are using an automated fuzz generator on a type with
|
||||||
|
// private fields.
|
||||||
|
func visitMessage(m Message) {
|
||||||
|
t := reflect.TypeOf(m)
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
derefed := t.Elem()
|
||||||
|
if derefed.Kind() != reflect.Struct {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := reflect.ValueOf(m)
|
||||||
|
elem := v.Elem()
|
||||||
|
for i := 0; i < elem.NumField(); i++ {
|
||||||
|
field := elem.FieldByIndex([]int{i})
|
||||||
|
fieldType := field.Type()
|
||||||
|
if fieldType.Implements(reflect.TypeOf((*Message)(nil)).Elem()) {
|
||||||
|
visitMessage(field.Interface().(Message))
|
||||||
|
}
|
||||||
|
if field.Kind() == reflect.Slice {
|
||||||
|
for i := 0; i < field.Len(); i++ {
|
||||||
|
elem := field.Index(i)
|
||||||
|
elemType := elem.Type()
|
||||||
|
if elemType.Implements(reflect.TypeOf((*Message)(nil)).Elem()) {
|
||||||
|
visitMessage(elem.Interface().(Message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if field := elem.FieldByName("XXX_unrecognized"); field.IsValid() {
|
||||||
|
field.Set(reflect.ValueOf([]byte{}))
|
||||||
|
}
|
||||||
|
if field := elem.FieldByName("XXX_extensions"); field.IsValid() {
|
||||||
|
field.Set(reflect.ValueOf(nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rndMessage generates a random valid Protocol Buffer message.
|
||||||
|
func rndMessage(r *rand.Rand) Message {
|
||||||
|
var t reflect.Type
|
||||||
|
switch v := rand.Intn(23); v {
|
||||||
|
// TODO(br): Uncomment the elements below once fix is incorporated, except
|
||||||
|
// for the elements marked as patently incompatible.
|
||||||
|
// case 0:
|
||||||
|
// t = reflect.TypeOf(&GoEnum{})
|
||||||
|
// break
|
||||||
|
// case 1:
|
||||||
|
// t = reflect.TypeOf(&GoTestField{})
|
||||||
|
// break
|
||||||
|
case 2:
|
||||||
|
t = reflect.TypeOf(&GoTest{})
|
||||||
|
break
|
||||||
|
// case 3:
|
||||||
|
// t = reflect.TypeOf(&GoSkipTest{})
|
||||||
|
// break
|
||||||
|
// case 4:
|
||||||
|
// t = reflect.TypeOf(&NonPackedTest{})
|
||||||
|
// break
|
||||||
|
// case 5:
|
||||||
|
// t = reflect.TypeOf(&PackedTest{})
|
||||||
|
// break
|
||||||
|
case 6:
|
||||||
|
t = reflect.TypeOf(&MaxTag{})
|
||||||
|
break
|
||||||
|
case 7:
|
||||||
|
t = reflect.TypeOf(&OldMessage{})
|
||||||
|
break
|
||||||
|
case 8:
|
||||||
|
t = reflect.TypeOf(&NewMessage{})
|
||||||
|
break
|
||||||
|
case 9:
|
||||||
|
t = reflect.TypeOf(&InnerMessage{})
|
||||||
|
break
|
||||||
|
case 10:
|
||||||
|
t = reflect.TypeOf(&OtherMessage{})
|
||||||
|
break
|
||||||
|
case 11:
|
||||||
|
// PATENTLY INVALID FOR FUZZ GENERATION
|
||||||
|
// t = reflect.TypeOf(&MyMessage{})
|
||||||
|
break
|
||||||
|
// case 12:
|
||||||
|
// t = reflect.TypeOf(&Ext{})
|
||||||
|
// break
|
||||||
|
case 13:
|
||||||
|
// PATENTLY INVALID FOR FUZZ GENERATION
|
||||||
|
// t = reflect.TypeOf(&MyMessageSet{})
|
||||||
|
break
|
||||||
|
// case 14:
|
||||||
|
// t = reflect.TypeOf(&Empty{})
|
||||||
|
// break
|
||||||
|
// case 15:
|
||||||
|
// t = reflect.TypeOf(&MessageList{})
|
||||||
|
// break
|
||||||
|
// case 16:
|
||||||
|
// t = reflect.TypeOf(&Strings{})
|
||||||
|
// break
|
||||||
|
// case 17:
|
||||||
|
// t = reflect.TypeOf(&Defaults{})
|
||||||
|
// break
|
||||||
|
// case 17:
|
||||||
|
// t = reflect.TypeOf(&SubDefaults{})
|
||||||
|
// break
|
||||||
|
// case 18:
|
||||||
|
// t = reflect.TypeOf(&RepeatedEnum{})
|
||||||
|
// break
|
||||||
|
case 19:
|
||||||
|
t = reflect.TypeOf(&MoreRepeated{})
|
||||||
|
break
|
||||||
|
// case 20:
|
||||||
|
// t = reflect.TypeOf(&GroupOld{})
|
||||||
|
// break
|
||||||
|
// case 21:
|
||||||
|
// t = reflect.TypeOf(&GroupNew{})
|
||||||
|
// break
|
||||||
|
case 22:
|
||||||
|
t = reflect.TypeOf(&FloatingPoint{})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
// TODO(br): Replace with an unreachable once fixed.
|
||||||
|
t = reflect.TypeOf(&GoTest{})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if t == nil {
|
||||||
|
t = reflect.TypeOf(&GoTest{})
|
||||||
|
}
|
||||||
|
v, ok := quick.Value(t, r)
|
||||||
|
if !ok {
|
||||||
|
panic("attempt to generate illegal item; consult item 11")
|
||||||
|
}
|
||||||
|
visitMessage(v.Interface().(Message))
|
||||||
|
return v.Interface().(Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// rndMessages generates several random Protocol Buffer messages.
|
||||||
|
func rndMessages(r *rand.Rand) []Message {
|
||||||
|
n := r.Intn(128)
|
||||||
|
out := make([]Message, 0, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
out = append(out, rndMessage(r))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuzz(t *testing.T) {
|
||||||
|
rnd := rand.New(rand.NewSource(42))
|
||||||
|
check := func() bool {
|
||||||
|
messages := rndMessages(rnd)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var written int
|
||||||
|
for i, msg := range messages {
|
||||||
|
n, err := WriteDelimited(&buf, msg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", messages, i, err)
|
||||||
|
}
|
||||||
|
written += n
|
||||||
|
}
|
||||||
|
var read int
|
||||||
|
for i, msg := range messages {
|
||||||
|
out := Clone(msg)
|
||||||
|
out.Reset()
|
||||||
|
n, _ := ReadDelimited(&buf, out)
|
||||||
|
read += n
|
||||||
|
if !Equal(out, msg) {
|
||||||
|
t.Fatalf("out = %v; want %v[%d] = %#v", out, messages, i, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if read != written {
|
||||||
|
t.Fatalf("%v read = %d; want %d", messages, read, written)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err := quick.Check(check, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
75
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/decode.go
generated
vendored
Normal file
75
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/decode.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInvalidVarint = errors.New("invalid varint32 encountered")
|
||||||
|
|
||||||
|
// ReadDelimited decodes a message from the provided length-delimited stream,
|
||||||
|
// where the length is encoded as 32-bit varint prefix to the message body.
|
||||||
|
// It returns the total number of bytes read and any applicable error. This is
|
||||||
|
// roughly equivalent to the companion Java API's
|
||||||
|
// MessageLite#parseDelimitedFrom. As per the reader contract, this function
|
||||||
|
// calls r.Read repeatedly as required until exactly one message including its
|
||||||
|
// prefix is read and decoded (or an error has occurred). The function never
|
||||||
|
// reads more bytes from the stream than required. The function never returns
|
||||||
|
// an error if a message has been read and decoded correctly, even if the end
|
||||||
|
// of the stream has been reached in doing so. In that case, any subsequent
|
||||||
|
// calls return (0, io.EOF).
|
||||||
|
func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) {
|
||||||
|
// Per AbstractParser#parsePartialDelimitedFrom with
|
||||||
|
// CodedInputStream#readRawVarint32.
|
||||||
|
headerBuf := make([]byte, binary.MaxVarintLen32)
|
||||||
|
var bytesRead, varIntBytes int
|
||||||
|
var messageLength uint64
|
||||||
|
for varIntBytes == 0 { // i.e. no varint has been decoded yet.
|
||||||
|
if bytesRead >= len(headerBuf) {
|
||||||
|
return bytesRead, errInvalidVarint
|
||||||
|
}
|
||||||
|
// We have to read byte by byte here to avoid reading more bytes
|
||||||
|
// than required. Each read byte is appended to what we have
|
||||||
|
// read before.
|
||||||
|
newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1])
|
||||||
|
if newBytesRead == 0 {
|
||||||
|
if err != nil {
|
||||||
|
return bytesRead, err
|
||||||
|
}
|
||||||
|
// A Reader should not return (0, nil), but if it does,
|
||||||
|
// it should be treated as no-op (according to the
|
||||||
|
// Reader contract). So let's go on...
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bytesRead += newBytesRead
|
||||||
|
// Now present everything read so far to the varint decoder and
|
||||||
|
// see if a varint can be decoded already.
|
||||||
|
messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead])
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBuf := make([]byte, messageLength)
|
||||||
|
newBytesRead, err := io.ReadFull(r, messageBuf)
|
||||||
|
bytesRead += newBytesRead
|
||||||
|
if err != nil {
|
||||||
|
return bytesRead, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead, proto.Unmarshal(messageBuf, m)
|
||||||
|
}
|
16
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/doc.go
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package ext enables record length-delimited Protocol Buffer streaming.
|
||||||
|
package ext
|
46
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/encode.go
generated
vendored
Normal file
46
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/encode.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteDelimited encodes and dumps a message to the provided writer prefixed
|
||||||
|
// with a 32-bit varint indicating the length of the encoded message, producing
|
||||||
|
// a length-delimited record stream, which can be used to chain together
|
||||||
|
// encoded messages of the same type together in a file. It returns the total
|
||||||
|
// number of bytes written and any applicable error. This is roughly
|
||||||
|
// equivalent to the companion Java API's MessageLite#writeDelimitedTo.
|
||||||
|
func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) {
|
||||||
|
buffer, err := proto.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, binary.MaxVarintLen32)
|
||||||
|
encodedLength := binary.PutUvarint(buf, uint64(len(buffer)))
|
||||||
|
|
||||||
|
sync, err := w.Write(buf[:encodedLength])
|
||||||
|
if err != nil {
|
||||||
|
return sync, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = w.Write(buffer)
|
||||||
|
return n + sync, err
|
||||||
|
}
|
103
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/fixtures_test.go
generated
vendored
Normal file
103
Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext/fixtures_test.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// http://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 ext
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
. "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FROM https://github.com/golang/protobuf/blob/master/proto/all_test.go.
|
||||||
|
|
||||||
|
func initGoTestField() *GoTestField {
|
||||||
|
f := new(GoTestField)
|
||||||
|
f.Label = String("label")
|
||||||
|
f.Type = String("type")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are all structurally equivalent but the tag numbers differ.
|
||||||
|
// (It's remarkable that required, optional, and repeated all have
|
||||||
|
// 8 letters.)
|
||||||
|
func initGoTest_RequiredGroup() *GoTest_RequiredGroup {
|
||||||
|
return &GoTest_RequiredGroup{
|
||||||
|
RequiredField: String("required"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGoTest_OptionalGroup() *GoTest_OptionalGroup {
|
||||||
|
return &GoTest_OptionalGroup{
|
||||||
|
RequiredField: String("optional"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup {
|
||||||
|
return &GoTest_RepeatedGroup{
|
||||||
|
RequiredField: String("repeated"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGoTest(setdefaults bool) *GoTest {
|
||||||
|
pb := new(GoTest)
|
||||||
|
if setdefaults {
|
||||||
|
pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted)
|
||||||
|
pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted)
|
||||||
|
pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted)
|
||||||
|
pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted)
|
||||||
|
pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted)
|
||||||
|
pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted)
|
||||||
|
pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted)
|
||||||
|
pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted)
|
||||||
|
pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted)
|
||||||
|
pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted)
|
||||||
|
pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted
|
||||||
|
pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted)
|
||||||
|
pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted)
|
||||||
|
}
|
||||||
|
|
||||||
|
pb.Kind = GoTest_TIME.Enum()
|
||||||
|
pb.RequiredField = initGoTestField()
|
||||||
|
pb.F_BoolRequired = Bool(true)
|
||||||
|
pb.F_Int32Required = Int32(3)
|
||||||
|
pb.F_Int64Required = Int64(6)
|
||||||
|
pb.F_Fixed32Required = Uint32(32)
|
||||||
|
pb.F_Fixed64Required = Uint64(64)
|
||||||
|
pb.F_Uint32Required = Uint32(3232)
|
||||||
|
pb.F_Uint64Required = Uint64(6464)
|
||||||
|
pb.F_FloatRequired = Float32(3232)
|
||||||
|
pb.F_DoubleRequired = Float64(6464)
|
||||||
|
pb.F_StringRequired = String("string")
|
||||||
|
pb.F_BytesRequired = []byte("bytes")
|
||||||
|
pb.F_Sint32Required = Int32(-32)
|
||||||
|
pb.F_Sint64Required = Int64(-64)
|
||||||
|
pb.Requiredgroup = initGoTest_RequiredGroup()
|
||||||
|
|
||||||
|
return pb
|
||||||
|
}
|
364
Godeps/_workspace/src/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
Normal file
364
Godeps/_workspace/src/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
// Code generated by protoc-gen-go.
|
||||||
|
// source: metrics.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package io_prometheus_client is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
metrics.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
LabelPair
|
||||||
|
Gauge
|
||||||
|
Counter
|
||||||
|
Quantile
|
||||||
|
Summary
|
||||||
|
Untyped
|
||||||
|
Histogram
|
||||||
|
Bucket
|
||||||
|
Metric
|
||||||
|
MetricFamily
|
||||||
|
*/
|
||||||
|
package io_prometheus_client
|
||||||
|
|
||||||
|
import proto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
type MetricType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
MetricType_COUNTER MetricType = 0
|
||||||
|
MetricType_GAUGE MetricType = 1
|
||||||
|
MetricType_SUMMARY MetricType = 2
|
||||||
|
MetricType_UNTYPED MetricType = 3
|
||||||
|
MetricType_HISTOGRAM MetricType = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
var MetricType_name = map[int32]string{
|
||||||
|
0: "COUNTER",
|
||||||
|
1: "GAUGE",
|
||||||
|
2: "SUMMARY",
|
||||||
|
3: "UNTYPED",
|
||||||
|
4: "HISTOGRAM",
|
||||||
|
}
|
||||||
|
var MetricType_value = map[string]int32{
|
||||||
|
"COUNTER": 0,
|
||||||
|
"GAUGE": 1,
|
||||||
|
"SUMMARY": 2,
|
||||||
|
"UNTYPED": 3,
|
||||||
|
"HISTOGRAM": 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x MetricType) Enum() *MetricType {
|
||||||
|
p := new(MetricType)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
func (x MetricType) String() string {
|
||||||
|
return proto.EnumName(MetricType_name, int32(x))
|
||||||
|
}
|
||||||
|
func (x *MetricType) UnmarshalJSON(data []byte) error {
|
||||||
|
value, err := proto.UnmarshalJSONEnum(MetricType_value, data, "MetricType")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*x = MetricType(value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelPair struct {
|
||||||
|
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||||
|
Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LabelPair) Reset() { *m = LabelPair{} }
|
||||||
|
func (m *LabelPair) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*LabelPair) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *LabelPair) GetName() string {
|
||||||
|
if m != nil && m.Name != nil {
|
||||||
|
return *m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LabelPair) GetValue() string {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Gauge struct {
|
||||||
|
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Gauge) Reset() { *m = Gauge{} }
|
||||||
|
func (m *Gauge) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Gauge) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Gauge) GetValue() float64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Counter) Reset() { *m = Counter{} }
|
||||||
|
func (m *Counter) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Counter) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Counter) GetValue() float64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Quantile struct {
|
||||||
|
Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"`
|
||||||
|
Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Quantile) Reset() { *m = Quantile{} }
|
||||||
|
func (m *Quantile) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Quantile) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Quantile) GetQuantile() float64 {
|
||||||
|
if m != nil && m.Quantile != nil {
|
||||||
|
return *m.Quantile
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Quantile) GetValue() float64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Summary struct {
|
||||||
|
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"`
|
||||||
|
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"`
|
||||||
|
Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Summary) Reset() { *m = Summary{} }
|
||||||
|
func (m *Summary) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Summary) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Summary) GetSampleCount() uint64 {
|
||||||
|
if m != nil && m.SampleCount != nil {
|
||||||
|
return *m.SampleCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Summary) GetSampleSum() float64 {
|
||||||
|
if m != nil && m.SampleSum != nil {
|
||||||
|
return *m.SampleSum
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Summary) GetQuantile() []*Quantile {
|
||||||
|
if m != nil {
|
||||||
|
return m.Quantile
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Untyped struct {
|
||||||
|
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Untyped) Reset() { *m = Untyped{} }
|
||||||
|
func (m *Untyped) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Untyped) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Untyped) GetValue() float64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Histogram struct {
|
||||||
|
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"`
|
||||||
|
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"`
|
||||||
|
Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) Reset() { *m = Histogram{} }
|
||||||
|
func (m *Histogram) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Histogram) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Histogram) GetSampleCount() uint64 {
|
||||||
|
if m != nil && m.SampleCount != nil {
|
||||||
|
return *m.SampleCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetSampleSum() float64 {
|
||||||
|
if m != nil && m.SampleSum != nil {
|
||||||
|
return *m.SampleSum
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetBucket() []*Bucket {
|
||||||
|
if m != nil {
|
||||||
|
return m.Bucket
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bucket struct {
|
||||||
|
CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count" json:"cumulative_count,omitempty"`
|
||||||
|
UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound" json:"upper_bound,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Bucket) Reset() { *m = Bucket{} }
|
||||||
|
func (m *Bucket) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Bucket) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Bucket) GetCumulativeCount() uint64 {
|
||||||
|
if m != nil && m.CumulativeCount != nil {
|
||||||
|
return *m.CumulativeCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Bucket) GetUpperBound() float64 {
|
||||||
|
if m != nil && m.UpperBound != nil {
|
||||||
|
return *m.UpperBound
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metric struct {
|
||||||
|
Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
|
||||||
|
Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"`
|
||||||
|
Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"`
|
||||||
|
Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"`
|
||||||
|
Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"`
|
||||||
|
Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"`
|
||||||
|
TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms" json:"timestamp_ms,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) Reset() { *m = Metric{} }
|
||||||
|
func (m *Metric) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Metric) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Metric) GetLabel() []*LabelPair {
|
||||||
|
if m != nil {
|
||||||
|
return m.Label
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetGauge() *Gauge {
|
||||||
|
if m != nil {
|
||||||
|
return m.Gauge
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetCounter() *Counter {
|
||||||
|
if m != nil {
|
||||||
|
return m.Counter
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetSummary() *Summary {
|
||||||
|
if m != nil {
|
||||||
|
return m.Summary
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetUntyped() *Untyped {
|
||||||
|
if m != nil {
|
||||||
|
return m.Untyped
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetHistogram() *Histogram {
|
||||||
|
if m != nil {
|
||||||
|
return m.Histogram
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) GetTimestampMs() int64 {
|
||||||
|
if m != nil && m.TimestampMs != nil {
|
||||||
|
return *m.TimestampMs
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetricFamily struct {
|
||||||
|
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||||
|
Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"`
|
||||||
|
Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"`
|
||||||
|
Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricFamily) Reset() { *m = MetricFamily{} }
|
||||||
|
func (m *MetricFamily) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*MetricFamily) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *MetricFamily) GetName() string {
|
||||||
|
if m != nil && m.Name != nil {
|
||||||
|
return *m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricFamily) GetHelp() string {
|
||||||
|
if m != nil && m.Help != nil {
|
||||||
|
return *m.Help
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricFamily) GetType() MetricType {
|
||||||
|
if m != nil && m.Type != nil {
|
||||||
|
return *m.Type
|
||||||
|
}
|
||||||
|
return MetricType_COUNTER
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricFamily) GetMetric() []*Metric {
|
||||||
|
if m != nil {
|
||||||
|
return m.Metric
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value)
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
The Prometheus project was started by Matt T. Proud (emeritus) and
|
||||||
|
Julius Volz in 2012.
|
||||||
|
|
||||||
|
Maintainers of this repository:
|
||||||
|
|
||||||
|
* Tobias Schmidt <ts@soundcloud.com>
|
||||||
|
|
||||||
|
The following individuals have contributed code to this repository
|
||||||
|
(listed in alphabetical order):
|
||||||
|
|
||||||
|
* Tobias Schmidt <ts@soundcloud.com>
|
18
Godeps/_workspace/src/github.com/prometheus/procfs/CONTRIBUTING.md
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/prometheus/procfs/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Prometheus uses GitHub to manage reviews of pull requests.
|
||||||
|
|
||||||
|
* If you have a trivial fix or improvement, go ahead and create a pull
|
||||||
|
request, addressing (with `@...`) one or more of the maintainers
|
||||||
|
(see [AUTHORS.md](AUTHORS.md)) in the description of the pull request.
|
||||||
|
|
||||||
|
* If you plan to do something more involved, first discuss your ideas
|
||||||
|
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||||
|
This will avoid unnecessary work and surely give you and us a good deal
|
||||||
|
of inspiration.
|
||||||
|
|
||||||
|
* Relevant coding style guidelines are the [Go Code Review
|
||||||
|
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
|
||||||
|
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
|
||||||
|
Practices for Production
|
||||||
|
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
|
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,7 @@
|
||||||
|
procfs provides functions to retrieve system, kernel and process
|
||||||
|
metrics from the pseudo-filesystem proc.
|
||||||
|
|
||||||
|
Copyright 2014-2015 The Prometheus Authors
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
SoundCloud Ltd. (http://soundcloud.com/).
|
|
@ -0,0 +1,11 @@
|
||||||
|
# procfs
|
||||||
|
|
||||||
|
This procfs package provides functions to retrieve system, kernel and process
|
||||||
|
metrics from the pseudo-filesystem proc.
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
|
||||||
|
[![Circle CI](https://circleci.com/gh/prometheus/procfs.svg?style=svg)](https://circleci.com/gh/prometheus/procfs)
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
$ go test
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2014 Prometheus Team
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package procfs provides functions to retrieve system, kernel and process
|
||||||
|
// metrics from the pseudo-filesystem proc.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "fmt"
|
||||||
|
// "log"
|
||||||
|
//
|
||||||
|
// "github.com/prometheus/procfs"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// p, err := procfs.Self()
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatalf("could not get process: %s", err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// stat, err := p.NewStat()
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatalf("could not get process stat: %s", err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fmt.Printf("command: %s\n", stat.Comm)
|
||||||
|
// fmt.Printf("cpu time: %fs\n", stat.CPUTime())
|
||||||
|
// fmt.Printf("vsize: %dB\n", stat.VirtualMemory())
|
||||||
|
// fmt.Printf("rss: %dB\n", stat.ResidentMemory())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
package procfs
|
BIN
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/cmdline
generated
vendored
Normal file
BIN
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/cmdline
generated
vendored
Normal file
Binary file not shown.
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/0
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/0
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/1
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/1
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/2
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/2
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/3
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/3
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/4
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/fd/4
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/limits
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/limits
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Limit Soft Limit Hard Limit Units
|
||||||
|
Max cpu time unlimited unlimited seconds
|
||||||
|
Max file size unlimited unlimited bytes
|
||||||
|
Max data size unlimited unlimited bytes
|
||||||
|
Max stack size 8388608 unlimited bytes
|
||||||
|
Max core file size 0 unlimited bytes
|
||||||
|
Max resident set unlimited unlimited bytes
|
||||||
|
Max processes 62898 62898 processes
|
||||||
|
Max open files 2048 4096 files
|
||||||
|
Max locked memory 65536 65536 bytes
|
||||||
|
Max address space unlimited unlimited bytes
|
||||||
|
Max file locks unlimited unlimited locks
|
||||||
|
Max pending signals 62898 62898 signals
|
||||||
|
Max msgqueue size 819200 819200 bytes
|
||||||
|
Max nice priority 0 0
|
||||||
|
Max realtime priority 0 0
|
||||||
|
Max realtime timeout unlimited unlimited us
|
1
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/stat
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/26231/stat
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
|
2
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/584/stat
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/prometheus/procfs/fixtures/584/stat
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0
|
||||||
|
#!/bin/cat /proc/self/stat
|
|
@ -0,0 +1,16 @@
|
||||||
|
cpu 301854 612 111922 8979004 3552 2 3944 0 0 0
|
||||||
|
cpu0 44490 19 21045 1087069 220 1 3410 0 0 0
|
||||||
|
cpu1 47869 23 16474 1110787 591 0 46 0 0 0
|
||||||
|
cpu2 46504 36 15916 1112321 441 0 326 0 0 0
|
||||||
|
cpu3 47054 102 15683 1113230 533 0 60 0 0 0
|
||||||
|
cpu4 28413 25 10776 1140321 217 0 8 0 0 0
|
||||||
|
cpu5 29271 101 11586 1136270 672 0 30 0 0 0
|
||||||
|
cpu6 29152 36 10276 1139721 319 0 29 0 0 0
|
||||||
|
cpu7 29098 268 10164 1139282 555 0 31 0 0 0
|
||||||
|
intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
|
ctxt 38014093
|
||||||
|
btime 1418183276
|
||||||
|
processes 26442
|
||||||
|
procs_running 2
|
||||||
|
procs_blocked 0
|
||||||
|
softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444
|
|
@ -0,0 +1,36 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FS represents the pseudo-filesystem proc, which provides an interface to
|
||||||
|
// kernel data structures.
|
||||||
|
type FS string
|
||||||
|
|
||||||
|
// DefaultMountPoint is the common mount point of the proc filesystem.
|
||||||
|
const DefaultMountPoint = "/proc"
|
||||||
|
|
||||||
|
// NewFS returns a new FS mounted under the given mountPoint. It will error
|
||||||
|
// if the mount point can't be read.
|
||||||
|
func NewFS(mountPoint string) (FS, error) {
|
||||||
|
info, err := os.Stat(mountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return FS(mountPoint), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs FS) stat(p string) (os.FileInfo, error) {
|
||||||
|
return os.Stat(path.Join(string(fs), p))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs FS) open(p string) (*os.File, error) {
|
||||||
|
return os.Open(path.Join(string(fs), p))
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestNewFS(t *testing.T) {
|
||||||
|
if _, err := NewFS("foobar"); err == nil {
|
||||||
|
t.Error("want NewFS to fail for non-existing mount point")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := NewFS("procfs.go"); err == nil {
|
||||||
|
t.Error("want NewFS to fail if mount point is not a directory")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Proc provides information about a running process.
|
||||||
|
type Proc struct {
|
||||||
|
// The process ID.
|
||||||
|
PID int
|
||||||
|
|
||||||
|
fs FS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procs represents a list of Proc structs.
|
||||||
|
type Procs []Proc
|
||||||
|
|
||||||
|
func (p Procs) Len() int { return len(p) }
|
||||||
|
func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
|
||||||
|
|
||||||
|
// Self returns a process for the current process.
|
||||||
|
func Self() (Proc, error) {
|
||||||
|
return NewProc(os.Getpid())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProc returns a process for the given pid under /proc.
|
||||||
|
func NewProc(pid int) (Proc, error) {
|
||||||
|
fs, err := NewFS(DefaultMountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return Proc{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.NewProc(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllProcs returns a list of all currently avaible processes under /proc.
|
||||||
|
func AllProcs() (Procs, error) {
|
||||||
|
fs, err := NewFS(DefaultMountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return Procs{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.AllProcs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProc returns a process for the given pid.
|
||||||
|
func (fs FS) NewProc(pid int) (Proc, error) {
|
||||||
|
if _, err := fs.stat(strconv.Itoa(pid)); err != nil {
|
||||||
|
return Proc{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Proc{PID: pid, fs: fs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllProcs returns a list of all currently avaible processes.
|
||||||
|
func (fs FS) AllProcs() (Procs, error) {
|
||||||
|
d, err := fs.open("")
|
||||||
|
if err != nil {
|
||||||
|
return Procs{}, err
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
|
||||||
|
names, err := d.Readdirnames(-1)
|
||||||
|
if err != nil {
|
||||||
|
return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := Procs{}
|
||||||
|
for _, n := range names {
|
||||||
|
pid, err := strconv.ParseInt(n, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p = append(p, Proc{PID: int(pid), fs: fs})
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CmdLine returns the command line of a process.
|
||||||
|
func (p Proc) CmdLine() ([]string, error) {
|
||||||
|
f, err := p.open("cmdline")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileDescriptors returns the currently open file descriptors of a process.
|
||||||
|
func (p Proc) FileDescriptors() ([]uintptr, error) {
|
||||||
|
names, err := p.fileDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fds := make([]uintptr, len(names))
|
||||||
|
for i, n := range names {
|
||||||
|
fd, err := strconv.ParseInt(n, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
|
||||||
|
}
|
||||||
|
fds[i] = uintptr(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileDescriptorsLen returns the number of currently open file descriptors of
|
||||||
|
// a process.
|
||||||
|
func (p Proc) FileDescriptorsLen() (int, error) {
|
||||||
|
fds, err := p.fileDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(fds), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Proc) fileDescriptors() ([]string, error) {
|
||||||
|
d, err := p.open("fd")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
|
||||||
|
names, err := d.Readdirnames(-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Proc) open(pa string) (*os.File, error) {
|
||||||
|
return p.fs.open(path.Join(strconv.Itoa(p.PID), pa))
|
||||||
|
}
|
111
Godeps/_workspace/src/github.com/prometheus/procfs/proc_limits.go
generated
vendored
Normal file
111
Godeps/_workspace/src/github.com/prometheus/procfs/proc_limits.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcLimits represents the soft limits for each of the process's resource
|
||||||
|
// limits.
|
||||||
|
type ProcLimits struct {
|
||||||
|
CPUTime int
|
||||||
|
FileSize int
|
||||||
|
DataSize int
|
||||||
|
StackSize int
|
||||||
|
CoreFileSize int
|
||||||
|
ResidentSet int
|
||||||
|
Processes int
|
||||||
|
OpenFiles int
|
||||||
|
LockedMemory int
|
||||||
|
AddressSpace int
|
||||||
|
FileLocks int
|
||||||
|
PendingSignals int
|
||||||
|
MsqqueueSize int
|
||||||
|
NicePriority int
|
||||||
|
RealtimePriority int
|
||||||
|
RealtimeTimeout int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
limitsFields = 3
|
||||||
|
limitsUnlimited = "unlimited"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
limitsDelimiter = regexp.MustCompile(" +")
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewLimits returns the current soft limits of the process.
|
||||||
|
func (p Proc) NewLimits() (ProcLimits, error) {
|
||||||
|
f, err := p.open("limits")
|
||||||
|
if err != nil {
|
||||||
|
return ProcLimits{}, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
l = ProcLimits{}
|
||||||
|
s = bufio.NewScanner(f)
|
||||||
|
)
|
||||||
|
for s.Scan() {
|
||||||
|
fields := limitsDelimiter.Split(s.Text(), limitsFields)
|
||||||
|
if len(fields) != limitsFields {
|
||||||
|
return ProcLimits{}, fmt.Errorf(
|
||||||
|
"couldn't parse %s line %s", f.Name(), s.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fields[0] {
|
||||||
|
case "Max cpu time":
|
||||||
|
l.CPUTime, err = parseInt(fields[1])
|
||||||
|
case "Max file size":
|
||||||
|
l.FileLocks, err = parseInt(fields[1])
|
||||||
|
case "Max data size":
|
||||||
|
l.DataSize, err = parseInt(fields[1])
|
||||||
|
case "Max stack size":
|
||||||
|
l.StackSize, err = parseInt(fields[1])
|
||||||
|
case "Max core file size":
|
||||||
|
l.CoreFileSize, err = parseInt(fields[1])
|
||||||
|
case "Max resident set":
|
||||||
|
l.ResidentSet, err = parseInt(fields[1])
|
||||||
|
case "Max processes":
|
||||||
|
l.Processes, err = parseInt(fields[1])
|
||||||
|
case "Max open files":
|
||||||
|
l.OpenFiles, err = parseInt(fields[1])
|
||||||
|
case "Max locked memory":
|
||||||
|
l.LockedMemory, err = parseInt(fields[1])
|
||||||
|
case "Max address space":
|
||||||
|
l.AddressSpace, err = parseInt(fields[1])
|
||||||
|
case "Max file locks":
|
||||||
|
l.FileLocks, err = parseInt(fields[1])
|
||||||
|
case "Max pending signals":
|
||||||
|
l.PendingSignals, err = parseInt(fields[1])
|
||||||
|
case "Max msgqueue size":
|
||||||
|
l.MsqqueueSize, err = parseInt(fields[1])
|
||||||
|
case "Max nice priority":
|
||||||
|
l.NicePriority, err = parseInt(fields[1])
|
||||||
|
case "Max realtime priority":
|
||||||
|
l.RealtimePriority, err = parseInt(fields[1])
|
||||||
|
case "Max realtime timeout":
|
||||||
|
l.RealtimeTimeout, err = parseInt(fields[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ProcLimits{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, s.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt(s string) (int, error) {
|
||||||
|
if s == limitsUnlimited {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(s, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
|
||||||
|
}
|
||||||
|
return int(i), nil
|
||||||
|
}
|
36
Godeps/_workspace/src/github.com/prometheus/procfs/proc_limits_test.go
generated
vendored
Normal file
36
Godeps/_workspace/src/github.com/prometheus/procfs/proc_limits_test.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestNewLimits(t *testing.T) {
|
||||||
|
fs, err := NewFS("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := fs.NewProc(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := p.NewLimits()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
want int
|
||||||
|
got int
|
||||||
|
}{
|
||||||
|
{name: "cpu time", want: -1, got: l.CPUTime},
|
||||||
|
{name: "open files", want: 2048, got: l.OpenFiles},
|
||||||
|
{name: "msgqueue size", want: 819200, got: l.MsqqueueSize},
|
||||||
|
{name: "nice priority", want: 0, got: l.NicePriority},
|
||||||
|
{name: "address space", want: -1, got: l.AddressSpace},
|
||||||
|
} {
|
||||||
|
if test.want != test.got {
|
||||||
|
t.Errorf("want %s %d, got %d", test.name, test.want, test.got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include <unistd.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// ProcStat provides status information about the process,
|
||||||
|
// read from /proc/[pid]/stat.
|
||||||
|
type ProcStat struct {
|
||||||
|
// The process ID.
|
||||||
|
PID int
|
||||||
|
// The filename of the executable.
|
||||||
|
Comm string
|
||||||
|
// The process state.
|
||||||
|
State string
|
||||||
|
// The PID of the parent of this process.
|
||||||
|
PPID int
|
||||||
|
// The process group ID of the process.
|
||||||
|
PGRP int
|
||||||
|
// The session ID of the process.
|
||||||
|
Session int
|
||||||
|
// The controlling terminal of the process.
|
||||||
|
TTY int
|
||||||
|
// The ID of the foreground process group of the controlling terminal of
|
||||||
|
// the process.
|
||||||
|
TPGID int
|
||||||
|
// The kernel flags word of the process.
|
||||||
|
Flags uint
|
||||||
|
// The number of minor faults the process has made which have not required
|
||||||
|
// loading a memory page from disk.
|
||||||
|
MinFlt uint
|
||||||
|
// The number of minor faults that the process's waited-for children have
|
||||||
|
// made.
|
||||||
|
CMinFlt uint
|
||||||
|
// The number of major faults the process has made which have required
|
||||||
|
// loading a memory page from disk.
|
||||||
|
MajFlt uint
|
||||||
|
// The number of major faults that the process's waited-for children have
|
||||||
|
// made.
|
||||||
|
CMajFlt uint
|
||||||
|
// Amount of time that this process has been scheduled in user mode,
|
||||||
|
// measured in clock ticks.
|
||||||
|
UTime uint
|
||||||
|
// Amount of time that this process has been scheduled in kernel mode,
|
||||||
|
// measured in clock ticks.
|
||||||
|
STime uint
|
||||||
|
// Amount of time that this process's waited-for children have been
|
||||||
|
// scheduled in user mode, measured in clock ticks.
|
||||||
|
CUTime uint
|
||||||
|
// Amount of time that this process's waited-for children have been
|
||||||
|
// scheduled in kernel mode, measured in clock ticks.
|
||||||
|
CSTime uint
|
||||||
|
// For processes running a real-time scheduling policy, this is the negated
|
||||||
|
// scheduling priority, minus one.
|
||||||
|
Priority int
|
||||||
|
// The nice value, a value in the range 19 (low priority) to -20 (high
|
||||||
|
// priority).
|
||||||
|
Nice int
|
||||||
|
// Number of threads in this process.
|
||||||
|
NumThreads int
|
||||||
|
// The time the process started after system boot, the value is expressed
|
||||||
|
// in clock ticks.
|
||||||
|
Starttime uint64
|
||||||
|
// Virtual memory size in bytes.
|
||||||
|
VSize int
|
||||||
|
// Resident set size in pages.
|
||||||
|
RSS int
|
||||||
|
|
||||||
|
fs FS
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStat returns the current status information of the process.
|
||||||
|
func (p Proc) NewStat() (ProcStat, error) {
|
||||||
|
f, err := p.open("stat")
|
||||||
|
if err != nil {
|
||||||
|
return ProcStat{}, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return ProcStat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ignore int
|
||||||
|
|
||||||
|
s = ProcStat{PID: p.PID, fs: p.fs}
|
||||||
|
l = bytes.Index(data, []byte("("))
|
||||||
|
r = bytes.LastIndex(data, []byte(")"))
|
||||||
|
)
|
||||||
|
|
||||||
|
if l < 0 || r < 0 {
|
||||||
|
return ProcStat{}, fmt.Errorf(
|
||||||
|
"unexpected format, couldn't extract comm: %s",
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Comm = string(data[l+1 : r])
|
||||||
|
_, err = fmt.Fscan(
|
||||||
|
bytes.NewBuffer(data[r+2:]),
|
||||||
|
&s.State,
|
||||||
|
&s.PPID,
|
||||||
|
&s.PGRP,
|
||||||
|
&s.Session,
|
||||||
|
&s.TTY,
|
||||||
|
&s.TPGID,
|
||||||
|
&s.Flags,
|
||||||
|
&s.MinFlt,
|
||||||
|
&s.CMinFlt,
|
||||||
|
&s.MajFlt,
|
||||||
|
&s.CMajFlt,
|
||||||
|
&s.UTime,
|
||||||
|
&s.STime,
|
||||||
|
&s.CUTime,
|
||||||
|
&s.CSTime,
|
||||||
|
&s.Priority,
|
||||||
|
&s.Nice,
|
||||||
|
&s.NumThreads,
|
||||||
|
&ignore,
|
||||||
|
&s.Starttime,
|
||||||
|
&s.VSize,
|
||||||
|
&s.RSS,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return ProcStat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VirtualMemory returns the virtual memory size in bytes.
|
||||||
|
func (s ProcStat) VirtualMemory() int {
|
||||||
|
return s.VSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResidentMemory returns the resident memory size in bytes.
|
||||||
|
func (s ProcStat) ResidentMemory() int {
|
||||||
|
return s.RSS * os.Getpagesize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTime returns the unix timestamp of the process in seconds.
|
||||||
|
func (s ProcStat) StartTime() (float64, error) {
|
||||||
|
stat, err := s.fs.NewStat()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return float64(stat.BootTime) + (float64(s.Starttime) / ticks()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPUTime returns the total CPU user and system time in seconds.
|
||||||
|
func (s ProcStat) CPUTime() float64 {
|
||||||
|
return float64(s.UTime+s.STime) / ticks()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ticks() float64 {
|
||||||
|
return float64(C.sysconf(C._SC_CLK_TCK)) // most likely 100
|
||||||
|
}
|
112
Godeps/_workspace/src/github.com/prometheus/procfs/proc_stat_test.go
generated
vendored
Normal file
112
Godeps/_workspace/src/github.com/prometheus/procfs/proc_stat_test.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestProcStat(t *testing.T) {
|
||||||
|
fs, err := NewFS("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := fs.NewProc(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := p.NewStat()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
want int
|
||||||
|
got int
|
||||||
|
}{
|
||||||
|
{name: "pid", want: 26231, got: s.PID},
|
||||||
|
{name: "user time", want: 1677, got: int(s.UTime)},
|
||||||
|
{name: "system time", want: 44, got: int(s.STime)},
|
||||||
|
{name: "start time", want: 82375, got: int(s.Starttime)},
|
||||||
|
{name: "virtual memory size", want: 56274944, got: s.VSize},
|
||||||
|
{name: "resident set size", want: 1981, got: s.RSS},
|
||||||
|
} {
|
||||||
|
if test.want != test.got {
|
||||||
|
t.Errorf("want %s %d, got %d", test.name, test.want, test.got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcStatComm(t *testing.T) {
|
||||||
|
s1, err := testProcStat(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := "vim", s1.Comm; want != got {
|
||||||
|
t.Errorf("want comm %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, err := testProcStat(584)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := "(a b ) ( c d) ", s2.Comm; want != got {
|
||||||
|
t.Errorf("want comm %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcStatVirtualMemory(t *testing.T) {
|
||||||
|
s, err := testProcStat(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if want, got := 56274944, s.VirtualMemory(); want != got {
|
||||||
|
t.Errorf("want virtual memory %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcStatResidentMemory(t *testing.T) {
|
||||||
|
s, err := testProcStat(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if want, got := 1981*4096, s.ResidentMemory(); want != got {
|
||||||
|
t.Errorf("want resident memory %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcStatStartTime(t *testing.T) {
|
||||||
|
s, err := testProcStat(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time, err := s.StartTime()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := 1418184099.75, time; want != got {
|
||||||
|
t.Errorf("want start time %f, got %f", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcStatCPUTime(t *testing.T) {
|
||||||
|
s, err := testProcStat(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if want, got := 17.21, s.CPUTime(); want != got {
|
||||||
|
t.Errorf("want cpu time %f, got %f", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testProcStat(pid int) (ProcStat, error) {
|
||||||
|
p, err := testProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
return ProcStat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.NewStat()
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSelf(t *testing.T) {
|
||||||
|
p1, err := NewProc(os.Getpid())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p2, err := Self()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(p1, p2) {
|
||||||
|
t.Errorf("want process %v to equal %v", p1, p2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllProcs(t *testing.T) {
|
||||||
|
fs, err := NewFS("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
procs, err := fs.AllProcs()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sort.Sort(procs)
|
||||||
|
for i, p := range []*Proc{{PID: 584}, {PID: 26231}} {
|
||||||
|
if want, got := p.PID, procs[i].PID; want != got {
|
||||||
|
t.Errorf("want processes %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdLine(t *testing.T) {
|
||||||
|
p1, err := testProcess(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
c, err := p1.CmdLine()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want := []string{"vim", "test.go", "+10"}; !reflect.DeepEqual(want, c) {
|
||||||
|
t.Errorf("want cmdline %v, got %v", want, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileDescriptors(t *testing.T) {
|
||||||
|
p1, err := testProcess(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fds, err := p1.FileDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sort.Sort(byUintptr(fds))
|
||||||
|
if want := []uintptr{0, 1, 2, 3, 4}; !reflect.DeepEqual(want, fds) {
|
||||||
|
t.Errorf("want fds %v, got %v", want, fds)
|
||||||
|
}
|
||||||
|
|
||||||
|
p2, err := Self()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fdsBefore, err := p2.FileDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := os.Open("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
fdsAfter, err := p2.FileDescriptors()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fdsBefore)+1 != len(fdsAfter) {
|
||||||
|
t.Errorf("want fds %v+1 to equal %v", fdsBefore, fdsAfter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileDescriptorsLen(t *testing.T) {
|
||||||
|
p1, err := testProcess(26231)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l, err := p1.FileDescriptorsLen()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := 5, l; want != got {
|
||||||
|
t.Errorf("want fds %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testProcess(pid int) (Proc, error) {
|
||||||
|
fs, err := NewFS("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
return Proc{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.NewProc(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
type byUintptr []uintptr
|
||||||
|
|
||||||
|
func (a byUintptr) Len() int { return len(a) }
|
||||||
|
func (a byUintptr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a byUintptr) Less(i, j int) bool { return a[i] < a[j] }
|
|
@ -0,0 +1,55 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stat represents kernel/system statistics.
|
||||||
|
type Stat struct {
|
||||||
|
// Boot time in seconds since the Epoch.
|
||||||
|
BootTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStat returns kernel/system statistics read from /proc/stat.
|
||||||
|
func NewStat() (Stat, error) {
|
||||||
|
fs, err := NewFS(DefaultMountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return Stat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.NewStat()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStat returns an information about current kernel/system statistics.
|
||||||
|
func (fs FS) NewStat() (Stat, error) {
|
||||||
|
f, err := fs.open("stat")
|
||||||
|
if err != nil {
|
||||||
|
return Stat{}, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
for s.Scan() {
|
||||||
|
line := s.Text()
|
||||||
|
if !strings.HasPrefix(line, "btime") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) != 2 {
|
||||||
|
return Stat{}, fmt.Errorf("couldn't parse %s line %s", f.Name(), line)
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(fields[1], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return Stat{}, fmt.Errorf("couldn't parse %s: %s", fields[1], err)
|
||||||
|
}
|
||||||
|
return Stat{BootTime: i}, nil
|
||||||
|
}
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stat{}, fmt.Errorf("couldn't parse %s, missing btime", f.Name())
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package procfs
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestStat(t *testing.T) {
|
||||||
|
fs, err := NewFS("fixtures")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := fs.NewStat()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if want, got := int64(1418183276), s.BootTime; want != got {
|
||||||
|
t.Errorf("want boot time %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
2
Makefile
2
Makefile
|
@ -91,7 +91,7 @@ advice: test
|
||||||
$(GO) vet ./...
|
$(GO) vet ./...
|
||||||
|
|
||||||
format:
|
format:
|
||||||
find . -iname '*.go' | grep -vE '^./(.build|_vendor)/' | xargs -n1 -P1 $(GOFMT) -w -s=true
|
find . -iname '*.go' | grep -vE '^./(.build|Godeps)/' | xargs -n1 -P1 $(GOFMT) -w -s=true
|
||||||
|
|
||||||
tag:
|
tag:
|
||||||
git tag $(VERSION)
|
git tag $(VERSION)
|
||||||
|
|
10
NOTICE
10
NOTICE
|
@ -16,3 +16,13 @@ perks - a fork of https://github.com/bmizerany/perks
|
||||||
https://github.com/beorn7/perks
|
https://github.com/beorn7/perks
|
||||||
Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
|
Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
|
||||||
See https://github.com/beorn7/perks/blob/master/README.md for license details.
|
See https://github.com/beorn7/perks/blob/master/README.md for license details.
|
||||||
|
|
||||||
|
Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
http://github.com/golang/protobuf/
|
||||||
|
Copyright 2010 The Go Authors
|
||||||
|
See source code for license details.
|
||||||
|
|
||||||
|
Support for streaming Protocol Buffer messages for the Go language (golang).
|
||||||
|
https://github.com/matttproud/golang_protobuf_extensions
|
||||||
|
Copyright 2013 Matt T. Proud
|
||||||
|
Licensed under the Apache License, Version 2.0
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Imported at 75cd24fc2f2c from https://bitbucket.org/ww/goautoneg.
|
|
|
@ -1 +0,0 @@
|
||||||
Imported at b965b613227fddccbfffe13eae360ed3fa822f8d from https://github.com/beorn7/perks .
|
|
|
@ -1,31 +0,0 @@
|
||||||
# Perks for Go (golang.org)
|
|
||||||
|
|
||||||
Perks contains the Go package quantile that computes approximate quantiles over
|
|
||||||
an unbounded data stream within low memory and CPU bounds.
|
|
||||||
|
|
||||||
For more information and examples, see:
|
|
||||||
http://godoc.org/github.com/bmizerany/perks
|
|
||||||
|
|
||||||
A very special thank you and shout out to Graham Cormode (Rutgers University),
|
|
||||||
Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and
|
|
||||||
Divesh Srivastava (AT&T Labs–Research) for their research and publication of
|
|
||||||
[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf)
|
|
||||||
|
|
||||||
Thank you, also:
|
|
||||||
* Armon Dadgar (@armon)
|
|
||||||
* Andrew Gerrand (@nf)
|
|
||||||
* Brad Fitzpatrick (@bradfitz)
|
|
||||||
* Keith Rarick (@kr)
|
|
||||||
|
|
||||||
FAQ:
|
|
||||||
|
|
||||||
Q: Why not move the quantile package into the project root?
|
|
||||||
A: I want to add more packages to perks later.
|
|
||||||
|
|
||||||
Copyright (C) 2013 Blake Mizerany
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,26 +0,0 @@
|
||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkInsert10Bins(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
h := New(10)
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsert100Bins(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
h := New(100)
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
// Package histogram provides a Go implementation of BigML's histogram package
|
|
||||||
// for Clojure/Java. It is currently experimental.
|
|
||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/heap"
|
|
||||||
"math"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bin struct {
|
|
||||||
Count int
|
|
||||||
Sum float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Bin) Update(x *Bin) {
|
|
||||||
b.Count += x.Count
|
|
||||||
b.Sum += x.Sum
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Bin) Mean() float64 {
|
|
||||||
return b.Sum / float64(b.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bins []*Bin
|
|
||||||
|
|
||||||
func (bs Bins) Len() int { return len(bs) }
|
|
||||||
func (bs Bins) Less(i, j int) bool { return bs[i].Mean() < bs[j].Mean() }
|
|
||||||
func (bs Bins) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] }
|
|
||||||
|
|
||||||
func (bs *Bins) Push(x interface{}) {
|
|
||||||
*bs = append(*bs, x.(*Bin))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bs *Bins) Pop() interface{} {
|
|
||||||
return bs.remove(len(*bs) - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bs *Bins) remove(n int) *Bin {
|
|
||||||
if n < 0 || len(*bs) < n {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x := (*bs)[n]
|
|
||||||
*bs = append((*bs)[:n], (*bs)[n+1:]...)
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
type Histogram struct {
|
|
||||||
res *reservoir
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(maxBins int) *Histogram {
|
|
||||||
return &Histogram{res: newReservoir(maxBins)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Histogram) Insert(f float64) {
|
|
||||||
h.res.insert(&Bin{1, f})
|
|
||||||
h.res.compress()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Histogram) Bins() Bins {
|
|
||||||
return h.res.bins
|
|
||||||
}
|
|
||||||
|
|
||||||
type reservoir struct {
|
|
||||||
n int
|
|
||||||
maxBins int
|
|
||||||
bins Bins
|
|
||||||
}
|
|
||||||
|
|
||||||
func newReservoir(maxBins int) *reservoir {
|
|
||||||
return &reservoir{maxBins: maxBins}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reservoir) insert(bin *Bin) {
|
|
||||||
r.n += bin.Count
|
|
||||||
i := sort.Search(len(r.bins), func(i int) bool {
|
|
||||||
return r.bins[i].Mean() >= bin.Mean()
|
|
||||||
})
|
|
||||||
if i < 0 || i == r.bins.Len() {
|
|
||||||
// TODO(blake): Maybe use an .insert(i, bin) instead of
|
|
||||||
// performing the extra work of a heap.Push.
|
|
||||||
heap.Push(&r.bins, bin)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.bins[i].Update(bin)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reservoir) compress() {
|
|
||||||
for r.bins.Len() > r.maxBins {
|
|
||||||
minGapIndex := -1
|
|
||||||
minGap := math.MaxFloat64
|
|
||||||
for i := 0; i < r.bins.Len()-1; i++ {
|
|
||||||
gap := gapWeight(r.bins[i], r.bins[i+1])
|
|
||||||
if minGap > gap {
|
|
||||||
minGap = gap
|
|
||||||
minGapIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev := r.bins[minGapIndex]
|
|
||||||
next := r.bins.remove(minGapIndex + 1)
|
|
||||||
prev.Update(next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func gapWeight(prev, next *Bin) float64 {
|
|
||||||
return next.Mean() - prev.Mean()
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHistogram(t *testing.T) {
|
|
||||||
const numPoints = 1e6
|
|
||||||
const maxBins = 3
|
|
||||||
|
|
||||||
h := New(maxBins)
|
|
||||||
for i := 0; i < numPoints; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
bins := h.Bins()
|
|
||||||
if g := len(bins); g > maxBins {
|
|
||||||
t.Fatalf("got %d bins, wanted <= %d", g, maxBins)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range bins {
|
|
||||||
t.Logf("%+v", b)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g := count(h.Bins()); g != numPoints {
|
|
||||||
t.Fatalf("binned %d points, wanted %d", g, numPoints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func count(bins Bins) int {
|
|
||||||
binCounts := 0
|
|
||||||
for _, b := range bins {
|
|
||||||
binCounts += b.Count
|
|
||||||
}
|
|
||||||
return binCounts
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package topk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// http://www.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf
|
|
||||||
|
|
||||||
type Element struct {
|
|
||||||
Value string
|
|
||||||
Count int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Samples []*Element
|
|
||||||
|
|
||||||
func (sm Samples) Len() int {
|
|
||||||
return len(sm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm Samples) Less(i, j int) bool {
|
|
||||||
return sm[i].Count < sm[j].Count
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm Samples) Swap(i, j int) {
|
|
||||||
sm[i], sm[j] = sm[j], sm[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stream struct {
|
|
||||||
k int
|
|
||||||
mon map[string]*Element
|
|
||||||
|
|
||||||
// the minimum Element
|
|
||||||
min *Element
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(k int) *Stream {
|
|
||||||
s := new(Stream)
|
|
||||||
s.k = k
|
|
||||||
s.mon = make(map[string]*Element)
|
|
||||||
s.min = &Element{}
|
|
||||||
|
|
||||||
// Track k+1 so that less frequenet items contended for that spot,
|
|
||||||
// resulting in k being more accurate.
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Insert(x string) {
|
|
||||||
s.insert(&Element{x, 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Merge(sm Samples) {
|
|
||||||
for _, e := range sm {
|
|
||||||
s.insert(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) insert(in *Element) {
|
|
||||||
e := s.mon[in.Value]
|
|
||||||
if e != nil {
|
|
||||||
e.Count++
|
|
||||||
} else {
|
|
||||||
if len(s.mon) < s.k+1 {
|
|
||||||
e = &Element{in.Value, in.Count}
|
|
||||||
s.mon[in.Value] = e
|
|
||||||
} else {
|
|
||||||
e = s.min
|
|
||||||
delete(s.mon, e.Value)
|
|
||||||
e.Value = in.Value
|
|
||||||
e.Count += in.Count
|
|
||||||
s.min = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if e.Count < s.min.Count {
|
|
||||||
s.min = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Query() Samples {
|
|
||||||
var sm Samples
|
|
||||||
for _, e := range s.mon {
|
|
||||||
sm = append(sm, e)
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sm))
|
|
||||||
|
|
||||||
if len(sm) < s.k {
|
|
||||||
return sm
|
|
||||||
}
|
|
||||||
|
|
||||||
return sm[:s.k]
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package topk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTopK(t *testing.T) {
|
|
||||||
stream := New(10)
|
|
||||||
ss := []*Stream{New(10), New(10), New(10)}
|
|
||||||
m := make(map[string]int)
|
|
||||||
for _, s := range ss {
|
|
||||||
for i := 0; i < 1e6; i++ {
|
|
||||||
v := fmt.Sprintf("%x", int8(rand.ExpFloat64()))
|
|
||||||
s.Insert(v)
|
|
||||||
m[v]++
|
|
||||||
}
|
|
||||||
stream.Merge(s.Query())
|
|
||||||
}
|
|
||||||
|
|
||||||
var sm Samples
|
|
||||||
for x, s := range m {
|
|
||||||
sm = append(sm, &Element{x, s})
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sm))
|
|
||||||
|
|
||||||
g := stream.Query()
|
|
||||||
if len(g) != 10 {
|
|
||||||
t.Fatalf("got %d, want 10", len(g))
|
|
||||||
}
|
|
||||||
for i, e := range g {
|
|
||||||
if sm[i].Value != e.Value {
|
|
||||||
t.Errorf("at %d: want %q, got %q", i, sm[i].Value, e.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQuery(t *testing.T) {
|
|
||||||
queryTests := []struct {
|
|
||||||
value string
|
|
||||||
expected int
|
|
||||||
}{
|
|
||||||
{"a", 1},
|
|
||||||
{"b", 2},
|
|
||||||
{"c", 2},
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := New(2)
|
|
||||||
for _, tt := range queryTests {
|
|
||||||
stream.Insert(tt.value)
|
|
||||||
if n := len(stream.Query()); n != tt.expected {
|
|
||||||
t.Errorf("want %d, got %d", tt.expected, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,10 +18,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/matttproud/golang_protobuf_extensions/ext"
|
||||||
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
"github.com/matttproud/golang_protobuf_extensions/ext"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/utility/test"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +45,8 @@ func (s *testProcessor001ProcessScenario) test(t testing.TB, set int) {
|
||||||
options := &ProcessOptions{
|
options := &ProcessOptions{
|
||||||
Timestamp: test001Time,
|
Timestamp: test001Time,
|
||||||
}
|
}
|
||||||
if err := Processor001.ProcessSingle(reader, s, options); !test.ErrorEqual(s.err, err) {
|
err = Processor001.ProcessSingle(reader, s, options)
|
||||||
|
if s.err != err && (s.err == nil || err == nil || err.Error() != s.err.Error()) {
|
||||||
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/utility/test"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,7 +48,8 @@ func (s *testProcessor002ProcessScenario) test(t testing.TB, set int) {
|
||||||
options := &ProcessOptions{
|
options := &ProcessOptions{
|
||||||
Timestamp: test002Time,
|
Timestamp: test002Time,
|
||||||
}
|
}
|
||||||
if err := Processor002.ProcessSingle(reader, s, options); !test.ErrorEqual(s.err, err) {
|
err = Processor002.ProcessSingle(reader, s, options)
|
||||||
|
if s.err != err && (s.err == nil || err == nil || err.Error() != s.err.Error()) {
|
||||||
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCounterAdd(t *testing.T) {
|
func TestCounterAdd(t *testing.T) {
|
||||||
|
|
|
@ -11,9 +11,8 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -16,10 +16,8 @@ package prometheus_test
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,8 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func listenGaugeStream(vals, result chan float64, done chan struct{}) {
|
func listenGaugeStream(vals, result chan float64, done chan struct{}) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGoCollector(t *testing.T) {
|
func TestGoCollector(t *testing.T) {
|
||||||
|
|
|
@ -20,10 +20,9 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Histogram counts individual observations from an event or sample stream in
|
// A Histogram counts individual observations from an event or sample stream in
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func benchmarkHistogramObserve(w int, b *testing.B) {
|
func benchmarkHistogramObserve(w int, b *testing.B) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type respBody string
|
type respBody string
|
||||||
|
|
|
@ -16,7 +16,7 @@ package prometheus
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Metric models a single sample value with its meta data being exported to
|
// A Metric models a single sample value with its meta data being exported to
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import "github.com/prometheus/procfs"
|
import "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/procfs"
|
||||||
|
|
||||||
func processCollectSupported() bool {
|
func processCollectSupported() bool {
|
||||||
if _, err := procfs.NewStat(); err == nil {
|
if _, err := procfs.NewStat(); err == nil {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/procfs"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/procfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProcessCollector(t *testing.T) {
|
func TestProcessCollector(t *testing.T) {
|
||||||
|
|
|
@ -33,11 +33,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/bitbucket.org/ww/goautoneg"
|
||||||
|
"github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/golang/protobuf/proto"
|
||||||
"github.com/golang/protobuf/proto"
|
dto "github.com/prometheus/client_golang/Godeps/_workspace/src/github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/_vendor/goautoneg"
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/client_golang/model"
|
||||||
"github.com/prometheus/client_golang/text"
|
"github.com/prometheus/client_golang/text"
|
||||||
)
|
)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue