Remove Google Code files, add GitHub files for protobuf lib.

This commit is contained in:
Julius Volz 2015-02-15 13:54:43 +01:00
parent af627bb2b9
commit 740a99a9ac
29 changed files with 1546 additions and 167 deletions

View file

@ -1,7 +1,7 @@
# Go support for Protocol Buffers - Google's data interchange format # Go support for Protocol Buffers - Google's data interchange format
# #
# Copyright 2010 The Go Authors. All rights reserved. # Copyright 2010 The Go Authors. All rights reserved.
# http://code.google.com/p/goprotobuf/ # https://github.com/golang/protobuf
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are # modification, are permitted provided that the following conditions are
@ -37,4 +37,7 @@ test: install generate-test-pbs
generate-test-pbs: generate-test-pbs:
make install && cd testdata && make make install
make -C testdata
make -C proto3_proto
make

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -45,7 +45,7 @@ import (
"time" "time"
. "./testdata" . "./testdata"
. "code.google.com/p/goprotobuf/proto" . "github.com/golang/protobuf/proto"
) )
var globalO *Buffer var globalO *Buffer
@ -1833,6 +1833,86 @@ func fuzzUnmarshal(t *testing.T, data []byte) {
Unmarshal(data, pb) Unmarshal(data, pb)
} }
func TestMapFieldMarshal(t *testing.T) {
m := &MessageWithMap{
NameMapping: map[int32]string{
1: "Rob",
4: "Ian",
8: "Dave",
},
}
b, err := Marshal(m)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
// b should be the concatenation of these three byte sequences in some order.
parts := []string{
"\n\a\b\x01\x12\x03Rob",
"\n\a\b\x04\x12\x03Ian",
"\n\b\b\x08\x12\x04Dave",
}
ok := false
for i := range parts {
for j := range parts {
if j == i {
continue
}
for k := range parts {
if k == i || k == j {
continue
}
try := parts[i] + parts[j] + parts[k]
if bytes.Equal(b, []byte(try)) {
ok = true
break
}
}
}
}
if !ok {
t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2])
}
t.Logf("FYI b: %q", b)
(new(Buffer)).DebugPrint("Dump of b", b)
}
func TestMapFieldRoundTrips(t *testing.T) {
m := &MessageWithMap{
NameMapping: map[int32]string{
1: "Rob",
4: "Ian",
8: "Dave",
},
MsgMapping: map[int64]*FloatingPoint{
0x7001: &FloatingPoint{F: Float64(2.0)},
},
ByteMapping: map[bool][]byte{
false: []byte("that's not right!"),
true: []byte("aye, 'tis true!"),
},
}
b, err := Marshal(m)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
t.Logf("FYI b: %q", b)
m2 := new(MessageWithMap)
if err := Unmarshal(b, m2); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
for _, pair := range [][2]interface{}{
{m.NameMapping, m2.NameMapping},
{m.MsgMapping, m2.MsgMapping},
{m.ByteMapping, m2.ByteMapping},
} {
if !reflect.DeepEqual(pair[0], pair[1]) {
t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1])
}
}
}
// Benchmarks // Benchmarks
func testMsg() *GoTest { func testMsg() *GoTest {

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer deep copy. // Protocol buffer deep copy and merge.
// TODO: MessageSet and RawMessage. // TODO: MessageSet and RawMessage.
package proto package proto
@ -113,6 +113,29 @@ func mergeAny(out, in reflect.Value) {
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
reflect.String, reflect.Uint32, reflect.Uint64: reflect.String, reflect.Uint32, reflect.Uint64:
out.Set(in) 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: case reflect.Ptr:
if in.IsNil() { if in.IsNil() {
return return
@ -125,6 +148,14 @@ func mergeAny(out, in reflect.Value) {
if in.IsNil() { if in.IsNil() {
return 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() n := in.Len()
if out.IsNil() { if out.IsNil() {
out.Set(reflect.MakeSlice(in.Type(), 0, n)) out.Set(reflect.MakeSlice(in.Type(), 0, n))
@ -133,9 +164,6 @@ func mergeAny(out, in reflect.Value) {
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
reflect.String, reflect.Uint32, reflect.Uint64: reflect.String, reflect.Uint32, reflect.Uint64:
out.Set(reflect.AppendSlice(out, in)) out.Set(reflect.AppendSlice(out, in))
case reflect.Uint8:
// []byte is a scalar bytes field.
out.Set(in)
default: default:
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
x := reflect.Indirect(reflect.New(in.Type().Elem())) x := reflect.Indirect(reflect.New(in.Type().Elem()))

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -34,7 +34,7 @@ package proto_test
import ( import (
"testing" "testing"
"code.google.com/p/goprotobuf/proto" "github.com/golang/protobuf/proto"
pb "./testdata" pb "./testdata"
) )
@ -79,6 +79,22 @@ func TestClone(t *testing.T) {
if proto.Equal(m, cloneTestMessage) { if proto.Equal(m, cloneTestMessage) {
t.Error("Mutating clone changed the original") 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) { func TestCloneNil(t *testing.T) {
@ -173,6 +189,31 @@ var mergeTests = []struct {
dst: &pb.OtherMessage{Value: []byte("bar")}, dst: &pb.OtherMessage{Value: []byte("bar")},
want: &pb.OtherMessage{Value: []byte("foo")}, 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) { func TestMerge(t *testing.T) {

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -178,7 +178,7 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
n, err := p.DecodeVarint() n, err := p.DecodeVarint()
if err != nil { if err != nil {
return return nil, err
} }
nb := int(n) nb := int(n)
@ -362,7 +362,7 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group
} }
tag := int(u >> 3) tag := int(u >> 3)
if tag <= 0 { if tag <= 0 {
return fmt.Errorf("proto: %s: illegal tag %d", st, tag) return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
} }
fieldnum, ok := prop.decoderTags.get(tag) fieldnum, ok := prop.decoderTags.get(tag)
if !ok { if !ok {
@ -465,6 +465,15 @@ func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
return nil 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. // Decode an int32.
func (o *Buffer) dec_int32(p *Properties, base structPointer) error { func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
u, err := p.valDec(o) u, err := p.valDec(o)
@ -475,6 +484,15 @@ func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
return nil 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. // Decode an int64.
func (o *Buffer) dec_int64(p *Properties, base structPointer) error { func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
u, err := p.valDec(o) u, err := p.valDec(o)
@ -485,15 +503,31 @@ func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
return nil 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. // Decode a string.
func (o *Buffer) dec_string(p *Properties, base structPointer) error { func (o *Buffer) dec_string(p *Properties, base structPointer) error {
s, err := o.DecodeStringBytes() s, err := o.DecodeStringBytes()
if err != nil { if err != nil {
return err return err
} }
sp := new(string) *structPointer_String(base, p.field) = &s
*sp = s return nil
*structPointer_String(base, p.field) = sp }
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 return nil
} }
@ -632,6 +666,72 @@ func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
return nil 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. // Decode a group.
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
bas := structPointer_GetStructPointer(base, p.field) bas := structPointer_GetStructPointer(base, p.field)

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -247,7 +247,7 @@ func (p *Buffer) Marshal(pb Message) error {
return ErrNil return ErrNil
} }
if err == nil { if err == nil {
err = p.enc_struct(t.Elem(), GetProperties(t.Elem()), base) err = p.enc_struct(GetProperties(t.Elem()), base)
} }
if collectStats { if collectStats {
@ -271,7 +271,7 @@ func Size(pb Message) (n int) {
return 0 return 0
} }
if err == nil { if err == nil {
n = size_struct(t.Elem(), GetProperties(t.Elem()), base) n = size_struct(GetProperties(t.Elem()), base)
} }
if collectStats { if collectStats {
@ -298,6 +298,16 @@ func (o *Buffer) enc_bool(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error {
v := *structPointer_BoolVal(base, p.field)
if !v {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
p.valEnc(o, 1)
return nil
}
func size_bool(p *Properties, base structPointer) int { func size_bool(p *Properties, base structPointer) int {
v := *structPointer_Bool(base, p.field) v := *structPointer_Bool(base, p.field)
if v == nil { if v == nil {
@ -306,6 +316,14 @@ func size_bool(p *Properties, base structPointer) int {
return len(p.tagcode) + 1 // each bool takes exactly one byte return len(p.tagcode) + 1 // each bool takes exactly one byte
} }
func size_proto3_bool(p *Properties, base structPointer) int {
v := *structPointer_BoolVal(base, p.field)
if !v {
return 0
}
return len(p.tagcode) + 1 // each bool takes exactly one byte
}
// Encode an int32. // Encode an int32.
func (o *Buffer) enc_int32(p *Properties, base structPointer) error { func (o *Buffer) enc_int32(p *Properties, base structPointer) error {
v := structPointer_Word32(base, p.field) v := structPointer_Word32(base, p.field)
@ -318,6 +336,17 @@ func (o *Buffer) enc_int32(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error {
v := structPointer_Word32Val(base, p.field)
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
if x == 0 {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
p.valEnc(o, uint64(x))
return nil
}
func size_int32(p *Properties, base structPointer) (n int) { func size_int32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32(base, p.field) v := structPointer_Word32(base, p.field)
if word32_IsNil(v) { if word32_IsNil(v) {
@ -329,6 +358,17 @@ func size_int32(p *Properties, base structPointer) (n int) {
return return
} }
func size_proto3_int32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32Val(base, p.field)
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
if x == 0 {
return 0
}
n += len(p.tagcode)
n += p.valSize(uint64(x))
return
}
// Encode a uint32. // Encode a uint32.
// Exactly the same as int32, except for no sign extension. // Exactly the same as int32, except for no sign extension.
func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { func (o *Buffer) enc_uint32(p *Properties, base structPointer) error {
@ -342,6 +382,17 @@ func (o *Buffer) enc_uint32(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error {
v := structPointer_Word32Val(base, p.field)
x := word32Val_Get(v)
if x == 0 {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
p.valEnc(o, uint64(x))
return nil
}
func size_uint32(p *Properties, base structPointer) (n int) { func size_uint32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32(base, p.field) v := structPointer_Word32(base, p.field)
if word32_IsNil(v) { if word32_IsNil(v) {
@ -353,6 +404,17 @@ func size_uint32(p *Properties, base structPointer) (n int) {
return return
} }
func size_proto3_uint32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32Val(base, p.field)
x := word32Val_Get(v)
if x == 0 {
return 0
}
n += len(p.tagcode)
n += p.valSize(uint64(x))
return
}
// Encode an int64. // Encode an int64.
func (o *Buffer) enc_int64(p *Properties, base structPointer) error { func (o *Buffer) enc_int64(p *Properties, base structPointer) error {
v := structPointer_Word64(base, p.field) v := structPointer_Word64(base, p.field)
@ -365,6 +427,17 @@ func (o *Buffer) enc_int64(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error {
v := structPointer_Word64Val(base, p.field)
x := word64Val_Get(v)
if x == 0 {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
p.valEnc(o, x)
return nil
}
func size_int64(p *Properties, base structPointer) (n int) { func size_int64(p *Properties, base structPointer) (n int) {
v := structPointer_Word64(base, p.field) v := structPointer_Word64(base, p.field)
if word64_IsNil(v) { if word64_IsNil(v) {
@ -376,6 +449,17 @@ func size_int64(p *Properties, base structPointer) (n int) {
return return
} }
func size_proto3_int64(p *Properties, base structPointer) (n int) {
v := structPointer_Word64Val(base, p.field)
x := word64Val_Get(v)
if x == 0 {
return 0
}
n += len(p.tagcode)
n += p.valSize(x)
return
}
// Encode a string. // Encode a string.
func (o *Buffer) enc_string(p *Properties, base structPointer) error { func (o *Buffer) enc_string(p *Properties, base structPointer) error {
v := *structPointer_String(base, p.field) v := *structPointer_String(base, p.field)
@ -388,6 +472,16 @@ func (o *Buffer) enc_string(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error {
v := *structPointer_StringVal(base, p.field)
if v == "" {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
o.EncodeStringBytes(v)
return nil
}
func size_string(p *Properties, base structPointer) (n int) { func size_string(p *Properties, base structPointer) (n int) {
v := *structPointer_String(base, p.field) v := *structPointer_String(base, p.field)
if v == nil { if v == nil {
@ -399,6 +493,16 @@ func size_string(p *Properties, base structPointer) (n int) {
return return
} }
func size_proto3_string(p *Properties, base structPointer) (n int) {
v := *structPointer_StringVal(base, p.field)
if v == "" {
return 0
}
n += len(p.tagcode)
n += sizeStringBytes(v)
return
}
// All protocol buffer fields are nillable, but be careful. // All protocol buffer fields are nillable, but be careful.
func isNil(v reflect.Value) bool { func isNil(v reflect.Value) bool {
switch v.Kind() { switch v.Kind() {
@ -429,7 +533,7 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
} }
o.buf = append(o.buf, p.tagcode...) o.buf = append(o.buf, p.tagcode...)
return o.enc_len_struct(p.stype, p.sprop, structp, &state) return o.enc_len_struct(p.sprop, structp, &state)
} }
func size_struct_message(p *Properties, base structPointer) int { func size_struct_message(p *Properties, base structPointer) int {
@ -448,7 +552,7 @@ func size_struct_message(p *Properties, base structPointer) int {
} }
n0 := len(p.tagcode) n0 := len(p.tagcode)
n1 := size_struct(p.stype, p.sprop, structp) n1 := size_struct(p.sprop, structp)
n2 := sizeVarint(uint64(n1)) // size of encoded length n2 := sizeVarint(uint64(n1)) // size of encoded length
return n0 + n1 + n2 return n0 + n1 + n2
} }
@ -462,7 +566,7 @@ func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
} }
o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
err := o.enc_struct(p.stype, p.sprop, b) err := o.enc_struct(p.sprop, b)
if err != nil && !state.shouldContinue(err, nil) { if err != nil && !state.shouldContinue(err, nil) {
return err return err
} }
@ -477,7 +581,7 @@ func size_struct_group(p *Properties, base structPointer) (n int) {
} }
n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup))
n += size_struct(p.stype, p.sprop, b) n += size_struct(p.sprop, b)
n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup))
return return
} }
@ -551,6 +655,16 @@ func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error {
return nil return nil
} }
func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error {
s := *structPointer_Bytes(base, p.field)
if len(s) == 0 {
return ErrNil
}
o.buf = append(o.buf, p.tagcode...)
o.EncodeRawBytes(s)
return nil
}
func size_slice_byte(p *Properties, base structPointer) (n int) { func size_slice_byte(p *Properties, base structPointer) (n int) {
s := *structPointer_Bytes(base, p.field) s := *structPointer_Bytes(base, p.field)
if s == nil { if s == nil {
@ -561,6 +675,16 @@ func size_slice_byte(p *Properties, base structPointer) (n int) {
return return
} }
func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
s := *structPointer_Bytes(base, p.field)
if len(s) == 0 {
return 0
}
n += len(p.tagcode)
n += sizeRawBytes(s)
return
}
// Encode a slice of int32s ([]int32). // Encode a slice of int32s ([]int32).
func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error {
s := structPointer_Word32Slice(base, p.field) s := structPointer_Word32Slice(base, p.field)
@ -831,7 +955,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
} }
o.buf = append(o.buf, p.tagcode...) o.buf = append(o.buf, p.tagcode...)
err := o.enc_len_struct(p.stype, p.sprop, structp, &state) err := o.enc_len_struct(p.sprop, structp, &state)
if err != nil && !state.shouldContinue(err, nil) { if err != nil && !state.shouldContinue(err, nil) {
if err == ErrNil { if err == ErrNil {
return ErrRepeatedHasNil return ErrRepeatedHasNil
@ -861,7 +985,7 @@ func size_slice_struct_message(p *Properties, base structPointer) (n int) {
continue continue
} }
n0 := size_struct(p.stype, p.sprop, structp) n0 := size_struct(p.sprop, structp)
n1 := sizeVarint(uint64(n0)) // size of encoded length n1 := sizeVarint(uint64(n0)) // size of encoded length
n += n0 + n1 n += n0 + n1
} }
@ -882,7 +1006,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error
o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
err := o.enc_struct(p.stype, p.sprop, b) err := o.enc_struct(p.sprop, b)
if err != nil && !state.shouldContinue(err, nil) { if err != nil && !state.shouldContinue(err, nil) {
if err == ErrNil { if err == ErrNil {
@ -908,7 +1032,7 @@ func size_slice_struct_group(p *Properties, base structPointer) (n int) {
return // return size up to this point return // return size up to this point
} }
n += size_struct(p.stype, p.sprop, b) n += size_struct(p.sprop, b)
} }
return return
} }
@ -945,12 +1069,112 @@ func size_map(p *Properties, base structPointer) int {
return sizeExtensionMap(v) return sizeExtensionMap(v)
} }
// Encode a map field.
func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
var state errorState // XXX: or do we need to plumb this through?
/*
A map defined as
map<key_type, value_type> map_field = N;
is encoded in the same way as
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = N;
*/
v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V
if v.Len() == 0 {
return nil
}
keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
enc := func() error {
if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil {
return err
}
if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil {
return err
}
return nil
}
keys := v.MapKeys()
sort.Sort(mapKeys(keys))
for _, key := range keys {
val := v.MapIndex(key)
keycopy.Set(key)
valcopy.Set(val)
o.buf = append(o.buf, p.tagcode...)
if err := o.enc_len_thing(enc, &state); err != nil {
return err
}
}
return nil
}
func size_new_map(p *Properties, base structPointer) int {
v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V
keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
n := 0
for _, key := range v.MapKeys() {
val := v.MapIndex(key)
keycopy.Set(key)
valcopy.Set(val)
// Tag codes are two bytes per map entry.
n += 2
n += p.mkeyprop.size(p.mkeyprop, keybase)
n += p.mvalprop.size(p.mvalprop, valbase)
}
return n
}
// mapEncodeScratch returns a new reflect.Value matching the map's value type,
// and a structPointer suitable for passing to an encoder or sizer.
func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) {
// Prepare addressable doubly-indirect placeholders for the key and value types.
// This is needed because the element-type encoders expect **T, but the map iteration produces T.
keycopy = reflect.New(mapType.Key()).Elem() // addressable K
keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K
keyptr.Set(keycopy.Addr()) //
keybase = toStructPointer(keyptr.Addr()) // **K
// Value types are more varied and require special handling.
switch mapType.Elem().Kind() {
case reflect.Slice:
// []byte
var dummy []byte
valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte
valbase = toStructPointer(valcopy.Addr())
case reflect.Ptr:
// message; the generated field type is map[K]*Msg (so V is *Msg),
// so we only need one level of indirection.
valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
valbase = toStructPointer(valcopy.Addr())
default:
// everything else
valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V
valptr.Set(valcopy.Addr()) //
valbase = toStructPointer(valptr.Addr()) // **V
}
return
}
// Encode a struct. // Encode a struct.
func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structPointer) error { func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
var state errorState var state errorState
// Encode fields in tag order so that decoders may use optimizations // Encode fields in tag order so that decoders may use optimizations
// that depend on the ordering. // that depend on the ordering.
// http://code.google.com/apis/protocolbuffers/docs/encoding.html#order // https://developers.google.com/protocol-buffers/docs/encoding#order
for _, i := range prop.order { for _, i := range prop.order {
p := prop.Prop[i] p := prop.Prop[i]
if p.enc != nil { if p.enc != nil {
@ -978,7 +1202,7 @@ func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structP
return state.err return state.err
} }
func size_struct(t reflect.Type, prop *StructProperties, base structPointer) (n int) { func size_struct(prop *StructProperties, base structPointer) (n int) {
for _, i := range prop.order { for _, i := range prop.order {
p := prop.Prop[i] p := prop.Prop[i]
if p.size != nil { if p.size != nil {
@ -998,11 +1222,16 @@ func size_struct(t reflect.Type, prop *StructProperties, base structPointer) (n
var zeroes [20]byte // longer than any conceivable sizeVarint var zeroes [20]byte // longer than any conceivable sizeVarint
// Encode a struct, preceded by its encoded length (as a varint). // Encode a struct, preceded by its encoded length (as a varint).
func (o *Buffer) enc_len_struct(t reflect.Type, prop *StructProperties, base structPointer, state *errorState) error { func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error {
return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state)
}
// Encode something, preceded by its encoded length (as a varint).
func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error {
iLen := len(o.buf) iLen := len(o.buf)
o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length
iMsg := len(o.buf) iMsg := len(o.buf)
err := o.enc_struct(t, prop, base) err := enc()
if err != nil && !state.shouldContinue(err, nil) { if err != nil && !state.shouldContinue(err, nil) {
return err return err
} }

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -57,7 +57,7 @@ Equality is defined in this way:
although represented by []byte, is not a repeated field) although represented by []byte, is not a repeated field)
- Two unset fields are equal. - Two unset fields are equal.
- Two unknown field sets are equal if their current - Two unknown field sets are equal if their current
encoded state is equal. (TODO) encoded state is equal.
- Two extension sets are equal iff they have corresponding - Two extension sets are equal iff they have corresponding
elements that are pairwise equal. elements that are pairwise equal.
- Every other combination of things are not equal. - Every other combination of things are not equal.
@ -154,6 +154,21 @@ func equalAny(v1, v2 reflect.Value) bool {
return v1.Float() == v2.Float() return v1.Float() == v2.Float()
case reflect.Int32, reflect.Int64: case reflect.Int32, reflect.Int64:
return v1.Int() == v2.Int() 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: case reflect.Ptr:
return equalAny(v1.Elem(), v2.Elem()) return equalAny(v1.Elem(), v2.Elem())
case reflect.Slice: case reflect.Slice:

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -35,7 +35,7 @@ import (
"testing" "testing"
pb "./testdata" pb "./testdata"
. "code.google.com/p/goprotobuf/proto" . "github.com/golang/protobuf/proto"
) )
// Four identical base messages. // Four identical base messages.
@ -155,6 +155,31 @@ var EqualTests = []struct {
}, },
true, 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) { func TestEqual(t *testing.T) {

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -227,7 +227,8 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er
return nil, err return nil, err
} }
e, ok := pb.ExtensionMap()[extension.Field] emap := pb.ExtensionMap()
e, ok := emap[extension.Field]
if !ok { if !ok {
return nil, ErrMissingExtension return nil, ErrMissingExtension
} }
@ -252,6 +253,7 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er
e.value = v e.value = v
e.desc = extension e.desc = extension
e.enc = nil e.enc = nil
emap[extension.Field] = e
return e.value, nil return e.value, nil
} }

View 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/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")
}
}

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -39,7 +39,7 @@
- Names are turned from camel_case to CamelCase for export. - Names are turned from camel_case to CamelCase for export.
- There are no methods on v to set fields; just treat - There are no methods on v to set fields; just treat
them as structure fields. them as structure fields.
- There are getters that return a field's value if set, - There are getters that return a field's value if set,
and return the field's default value if unset. and return the field's default value if unset.
The getters work even if the receiver is a nil message. The getters work even if the receiver is a nil message.
@ -50,17 +50,16 @@
That is, optional or required field int32 f becomes F *int32. That is, optional or required field int32 f becomes F *int32.
- Repeated fields are slices. - Repeated fields are slices.
- Helper functions are available to aid the setting of fields. - Helper functions are available to aid the setting of fields.
Helpers for getting values are superseded by the msg.Foo = proto.String("hello") // set field
GetFoo methods and their use is deprecated.
msg.Foo = proto.String("hello") // set field
- Constants are defined to hold the default values of all fields that - Constants are defined to hold the default values of all fields that
have them. They have the form Default_StructName_FieldName. have them. They have the form Default_StructName_FieldName.
Because the getter methods handle defaulted values, Because the getter methods handle defaulted values,
direct use of these constants should be rare. direct use of these constants should be rare.
- Enums are given type names and maps from names to values. - Enums are given type names and maps from names to values.
Enum values are prefixed with the enum's type name. Enum types have Enum values are prefixed by the enclosing message's name, or by the
a String method, and a Enum method to assist in message construction. enum's type name if it is a top-level enum. Enum types have a String
- Nested groups and enums have type names prefixed with the name of 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. the surrounding message type.
- Extensions are given descriptor names that start with E_, - Extensions are given descriptor names that start with E_,
followed by an underscore-delimited list of the nested messages followed by an underscore-delimited list of the nested messages
@ -74,7 +73,7 @@
package example; package example;
enum FOO { X = 17; }; enum FOO { X = 17; }
message Test { message Test {
required string label = 1; required string label = 1;
@ -89,7 +88,8 @@
package example package example
import "code.google.com/p/goprotobuf/proto" import proto "github.com/golang/protobuf/proto"
import math "math"
type FOO int32 type FOO int32
const ( const (
@ -110,6 +110,14 @@
func (x FOO) String() string { func (x FOO) String() string {
return proto.EnumName(FOO_name, int32(x)) 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 { type Test struct {
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
@ -118,41 +126,41 @@
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
} }
func (this *Test) Reset() { *this = Test{} } func (m *Test) Reset() { *m = Test{} }
func (this *Test) String() string { return proto.CompactTextString(this) } func (m *Test) String() string { return proto.CompactTextString(m) }
func (*Test) ProtoMessage() {}
const Default_Test_Type int32 = 77 const Default_Test_Type int32 = 77
func (this *Test) GetLabel() string { func (m *Test) GetLabel() string {
if this != nil && this.Label != nil { if m != nil && m.Label != nil {
return *this.Label return *m.Label
} }
return "" return ""
} }
func (this *Test) GetType() int32 { func (m *Test) GetType() int32 {
if this != nil && this.Type != nil { if m != nil && m.Type != nil {
return *this.Type return *m.Type
} }
return Default_Test_Type return Default_Test_Type
} }
func (this *Test) GetOptionalgroup() *Test_OptionalGroup { func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
if this != nil { if m != nil {
return this.Optionalgroup return m.Optionalgroup
} }
return nil return nil
} }
type Test_OptionalGroup struct { type Test_OptionalGroup struct {
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
XXX_unrecognized []byte `json:"-"`
} }
func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} } func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
func (this *Test_OptionalGroup) String() string { return proto.CompactTextString(this) } func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
func (this *Test_OptionalGroup) GetRequiredField() string { func (m *Test_OptionalGroup) GetRequiredField() string {
if this != nil && this.RequiredField != nil { if m != nil && m.RequiredField != nil {
return *this.RequiredField return *m.RequiredField
} }
return "" return ""
} }
@ -168,15 +176,15 @@
import ( import (
"log" "log"
"code.google.com/p/goprotobuf/proto" "github.com/golang/protobuf/proto"
"./example.pb" pb "./example.pb"
) )
func main() { func main() {
test := &example.Test{ test := &pb.Test{
Label: proto.String("hello"), Label: proto.String("hello"),
Type: proto.Int32(17), Type: proto.Int32(17),
Optionalgroup: &example.Test_OptionalGroup{ Optionalgroup: &pb.Test_OptionalGroup{
RequiredField: proto.String("good bye"), RequiredField: proto.String("good bye"),
}, },
} }
@ -184,7 +192,7 @@
if err != nil { if err != nil {
log.Fatal("marshaling error: ", err) log.Fatal("marshaling error: ", err)
} }
newTest := new(example.Test) newTest := &pb.Test{}
err = proto.Unmarshal(data, newTest) err = proto.Unmarshal(data, newTest)
if err != nil { if err != nil {
log.Fatal("unmarshaling error: ", err) log.Fatal("unmarshaling error: ", err)
@ -323,9 +331,7 @@ func Float64(v float64) *float64 {
// Uint32 is a helper routine that allocates a new uint32 value // Uint32 is a helper routine that allocates a new uint32 value
// to store v and returns a pointer to it. // to store v and returns a pointer to it.
func Uint32(v uint32) *uint32 { func Uint32(v uint32) *uint32 {
p := new(uint32) return &v
*p = v
return p
} }
// Uint64 is a helper routine that allocates a new uint64 value // Uint64 is a helper routine that allocates a new uint64 value
@ -738,3 +744,16 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
return dm 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())
}

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -36,7 +36,10 @@ package proto
*/ */
import ( import (
"bytes"
"encoding/json"
"errors" "errors"
"fmt"
"reflect" "reflect"
"sort" "sort"
) )
@ -211,6 +214,61 @@ func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
return nil 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. // A global registry of types that can be used in a MessageSet.
var messageSetMap = make(map[int32]messageSetDesc) var messageSetMap = make(map[int32]messageSetDesc)
@ -221,9 +279,9 @@ type messageSetDesc struct {
} }
// RegisterMessageSetType is called from the generated code. // RegisterMessageSetType is called from the generated code.
func RegisterMessageSetType(i messageTypeIder, name string) { func RegisterMessageSetType(m Message, fieldNum int32, name string) {
messageSetMap[i.MessageTypeId()] = messageSetDesc{ messageSetMap[fieldNum] = messageSetDesc{
t: reflect.TypeOf(i), t: reflect.TypeOf(m),
name: name, name: name,
} }
} }

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// +build appengine,!appenginevm // +build appengine
// This file contains an implementation of proto field accesses using package reflect. // 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 // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
@ -114,6 +114,11 @@ func structPointer_Bool(p structPointer, f field) **bool {
return structPointer_ifield(p, f).(**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. // BoolSlice returns the address of a []bool field in the struct.
func structPointer_BoolSlice(p structPointer, f field) *[]bool { func structPointer_BoolSlice(p structPointer, f field) *[]bool {
return structPointer_ifield(p, f).(*[]bool) return structPointer_ifield(p, f).(*[]bool)
@ -124,6 +129,11 @@ func structPointer_String(p structPointer, f field) **string {
return structPointer_ifield(p, f).(**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. // StringSlice returns the address of a []string field in the struct.
func structPointer_StringSlice(p structPointer, f field) *[]string { func structPointer_StringSlice(p structPointer, f field) *[]string {
return structPointer_ifield(p, f).(*[]string) return structPointer_ifield(p, f).(*[]string)
@ -134,6 +144,11 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return structPointer_ifield(p, f).(*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. // SetStructPointer writes a *struct field in the struct.
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
structPointer_field(p, f).Set(q.v) structPointer_field(p, f).Set(q.v)
@ -235,6 +250,49 @@ func structPointer_Word32(p structPointer, f field) word32 {
return word32{structPointer_field(p, f)} 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. // A word32Slice is a slice of 32-bit values.
// That is, v.Type() is []int32, []uint32, []float32, or []enum. // That is, v.Type() is []int32, []uint32, []float32, or []enum.
type word32Slice struct { type word32Slice struct {
@ -339,6 +397,43 @@ func structPointer_Word64(p structPointer, f field) word64 {
return word64{structPointer_field(p, f)} 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 { type word64Slice struct {
v reflect.Value v reflect.Value
} }

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// +build !appengine appenginevm // +build !appengine
// This file contains the implementation of the proto field accesses using package unsafe. // This file contains the implementation of the proto field accesses using package unsafe.
@ -100,6 +100,11 @@ func structPointer_Bool(p structPointer, f field) **bool {
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) 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. // BoolSlice returns the address of a []bool field in the struct.
func structPointer_BoolSlice(p structPointer, f field) *[]bool { func structPointer_BoolSlice(p structPointer, f field) *[]bool {
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
@ -110,6 +115,11 @@ func structPointer_String(p structPointer, f field) **string {
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) 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. // StringSlice returns the address of a []string field in the struct.
func structPointer_StringSlice(p structPointer, f field) *[]string { func structPointer_StringSlice(p structPointer, f field) *[]string {
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
@ -120,6 +130,11 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) 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. // SetStructPointer writes a *struct field in the struct.
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
@ -170,6 +185,24 @@ func structPointer_Word32(p structPointer, f field) word32 {
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) 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. // A word32Slice is a slice of 32-bit values.
type word32Slice []uint32 type word32Slice []uint32
@ -206,6 +239,21 @@ func structPointer_Word64(p structPointer, f field) word64 {
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) 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. // word64Slice is like word32Slice but for 64-bit values.
type word64Slice []uint64 type word64Slice []uint64

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -155,6 +155,7 @@ type Properties struct {
Repeated bool Repeated bool
Packed bool // relevant for repeated primitives only Packed bool // relevant for repeated primitives only
Enum string // set for enum types 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 Default string // default value
HasDefault bool // whether an explicit default was provided HasDefault bool // whether an explicit default was provided
@ -170,6 +171,10 @@ type Properties struct {
isMarshaler bool isMarshaler bool
isUnmarshaler 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 size sizer
valSize valueSizer // set for bool and numeric types only valSize valueSizer // set for bool and numeric types only
@ -200,6 +205,9 @@ func (p *Properties) String() string {
if p.OrigName != p.Name { if p.OrigName != p.Name {
s += ",name=" + p.OrigName s += ",name=" + p.OrigName
} }
if p.proto3 {
s += ",proto3"
}
if len(p.Enum) > 0 { if len(p.Enum) > 0 {
s += ",enum=" + p.Enum s += ",enum=" + p.Enum
} }
@ -274,6 +282,8 @@ func (p *Properties) Parse(s string) {
p.OrigName = f[5:] p.OrigName = f[5:]
case strings.HasPrefix(f, "enum="): case strings.HasPrefix(f, "enum="):
p.Enum = f[5:] p.Enum = f[5:]
case f == "proto3":
p.proto3 = true
case strings.HasPrefix(f, "def="): case strings.HasPrefix(f, "def="):
p.HasDefault = true p.HasDefault = true
p.Default = f[4:] // rest of string p.Default = f[4:] // rest of string
@ -293,19 +303,50 @@ func logNoSliceEnc(t1, t2 reflect.Type) {
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
// Initialize the fields for encoding and decoding. // Initialize the fields for encoding and decoding.
func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) { func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
p.enc = nil p.enc = nil
p.dec = nil p.dec = nil
p.size = nil p.size = nil
switch t1 := typ; t1.Kind() { switch t1 := typ; t1.Kind() {
default: default:
fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1) 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: case reflect.Ptr:
switch t2 := t1.Elem(); t2.Kind() { switch t2 := t1.Elem(); t2.Kind() {
default: default:
fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2) fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
break break
case reflect.Bool: case reflect.Bool:
p.enc = (*Buffer).enc_bool p.enc = (*Buffer).enc_bool
@ -399,6 +440,10 @@ func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
p.enc = (*Buffer).enc_slice_byte p.enc = (*Buffer).enc_slice_byte
p.dec = (*Buffer).dec_slice_byte p.dec = (*Buffer).dec_slice_byte
p.size = size_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: case reflect.Float32, reflect.Float64:
switch t2.Bits() { switch t2.Bits() {
case 32: case 32:
@ -461,6 +506,23 @@ func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
p.size = size_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 // precalculate tag code
@ -529,7 +591,7 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF
return return
} }
p.Parse(tag) p.Parse(tag)
p.setEncAndDec(typ, lockGetProp) p.setEncAndDec(typ, f, lockGetProp)
} }
var ( var (
@ -538,7 +600,11 @@ var (
) )
// GetProperties returns the list of properties for the type represented by t. // 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 { func GetProperties(t reflect.Type) *StructProperties {
if t.Kind() != reflect.Struct {
panic("proto: type must have kind struct")
}
mutex.Lock() mutex.Lock()
sprop := getPropertiesLocked(t) sprop := getPropertiesLocked(t)
mutex.Unlock() mutex.Unlock()

View 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

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -29,32 +29,30 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test syntax = "proto3";
import ( package proto3_proto;
"testing"
pb "./testdata" message Message {
"code.google.com/p/goprotobuf/proto" enum Humour {
) UNKNOWN = 0;
PUNS = 1;
SLAPSTICK = 2;
BILL_BAILEY = 3;
}
func TestGetExtensionsWithMissingExtensions(t *testing.T) { string name = 1;
msg := &pb.MyMessage{} Humour hilarity = 2;
ext1 := &pb.Ext{} uint32 height_in_cm = 3;
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil { bytes data = 4;
t.Fatalf("Could not set ext1: %s", ext1) int64 result_count = 7;
} bool true_scotsman = 8;
exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{ float score = 9;
pb.E_Ext_More,
pb.E_Ext_Text, repeated uint64 key = 5;
}) Nested nested = 6;
if err != nil { }
t.Fatalf("GetExtensions() failed: %s", err)
} message Nested {
if exts[0] != ext1 { string bunny = 1;
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])
}
} }

View 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/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)
}
}

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -35,8 +35,9 @@ import (
"log" "log"
"testing" "testing"
proto3pb "./proto3_proto"
pb "./testdata" pb "./testdata"
. "code.google.com/p/goprotobuf/proto" . "github.com/golang/protobuf/proto"
) )
var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)}
@ -102,6 +103,20 @@ var SizeTests = []struct {
{"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}},
{"extension (unencoded)", messageWithExtension1}, {"extension (unencoded)", messageWithExtension1},
{"extension (encoded)", messageWithExtension3}, {"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) { func TestSize(t *testing.T) {

View file

@ -1,7 +1,7 @@
# Go support for Protocol Buffers - Google's data interchange format # Go support for Protocol Buffers - Google's data interchange format
# #
# Copyright 2010 The Go Authors. All rights reserved. # Copyright 2010 The Go Authors. All rights reserved.
# http://code.google.com/p/goprotobuf/ # https://github.com/golang/protobuf
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are # modification, are permitted provided that the following conditions are
@ -37,11 +37,11 @@ all: regenerate
regenerate: regenerate:
rm -f test.pb.go rm -f test.pb.go
make test.pb.go make test.pb.go
# The following rules are just aids to development. Not needed for typical testing. # The following rules are just aids to development. Not needed for typical testing.
diff: regenerate diff: regenerate
hg diff test.pb.go git diff test.pb.go
restore: restore:
cp test.pb.go.golden test.pb.go cp test.pb.go.golden test.pb.go

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are

View file

@ -33,10 +33,11 @@ It has these top-level messages:
GroupOld GroupOld
GroupNew GroupNew
FloatingPoint FloatingPoint
MessageWithMap
*/ */
package testdata package testdata
import proto "code.google.com/p/goprotobuf/proto" import proto "github.com/golang/protobuf/proto"
import math "math" import math "math"
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -1416,6 +1417,12 @@ func (m *MyMessageSet) Marshal() ([]byte, error) {
func (m *MyMessageSet) Unmarshal(buf []byte) error { func (m *MyMessageSet) Unmarshal(buf []byte) error {
return proto.UnmarshalMessageSet(buf, m.ExtensionMap()) return proto.UnmarshalMessageSet(buf, m.ExtensionMap())
} }
func (m *MyMessageSet) MarshalJSON() ([]byte, error) {
return proto.MarshalMessageSetJSON(m.XXX_extensions)
}
func (m *MyMessageSet) UnmarshalJSON(buf []byte) error {
return proto.UnmarshalMessageSetJSON(buf, m.XXX_extensions)
}
// ensure MyMessageSet satisfies proto.Marshaler and proto.Unmarshaler // ensure MyMessageSet satisfies proto.Marshaler and proto.Unmarshaler
var _ proto.Marshaler = (*MyMessageSet)(nil) var _ proto.Marshaler = (*MyMessageSet)(nil)
@ -1879,6 +1886,38 @@ func (m *FloatingPoint) GetF() float64 {
return 0 return 0
} }
type MessageWithMap struct {
NameMapping map[int32]string `protobuf:"bytes,1,rep,name=name_mapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
MsgMapping map[int64]*FloatingPoint `protobuf:"bytes,2,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
ByteMapping map[bool][]byte `protobuf:"bytes,3,rep,name=byte_mapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
XXX_unrecognized []byte `json:"-"`
}
func (m *MessageWithMap) Reset() { *m = MessageWithMap{} }
func (m *MessageWithMap) String() string { return proto.CompactTextString(m) }
func (*MessageWithMap) ProtoMessage() {}
func (m *MessageWithMap) GetNameMapping() map[int32]string {
if m != nil {
return m.NameMapping
}
return nil
}
func (m *MessageWithMap) GetMsgMapping() map[int64]*FloatingPoint {
if m != nil {
return m.MsgMapping
}
return nil
}
func (m *MessageWithMap) GetByteMapping() map[bool][]byte {
if m != nil {
return m.ByteMapping
}
return nil
}
var E_Greeting = &proto.ExtensionDesc{ var E_Greeting = &proto.ExtensionDesc{
ExtendedType: (*MyMessage)(nil), ExtendedType: (*MyMessage)(nil),
ExtensionType: ([]string)(nil), ExtensionType: ([]string)(nil),

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -426,3 +426,9 @@ message GroupNew {
message FloatingPoint { message FloatingPoint {
required double f = 1; required double f = 1;
} }
message MessageWithMap {
map<int32, string> name_mapping = 1;
map<sint64, FloatingPoint> msg_mapping = 2;
map<bool, bytes> byte_mapping = 3;
}

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -36,6 +36,7 @@ package proto
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"encoding"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -74,13 +75,6 @@ type textWriter struct {
w writer w writer
} }
// textMarshaler is implemented by Messages that can marshal themsleves.
// It is identical to encoding.TextMarshaler, introduced in go 1.2,
// which will eventually replace it.
type textMarshaler interface {
MarshalText() (text []byte, err error)
}
func (w *textWriter) WriteString(s string) (n int, err error) { func (w *textWriter) WriteString(s string) (n int, err error) {
if !strings.Contains(s, "\n") { if !strings.Contains(s, "\n") {
if !w.compact && w.complete { if !w.compact && w.complete {
@ -250,6 +244,100 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
} }
continue 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 { if err := writeName(w, props); err != nil {
return err return err
@ -358,7 +446,7 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
} }
} }
w.indent() w.indent()
if tm, ok := v.Interface().(textMarshaler); ok { if tm, ok := v.Interface().(encoding.TextMarshaler); ok {
text, err := tm.MarshalText() text, err := tm.MarshalText()
if err != nil { if err != nil {
return err return err
@ -653,7 +741,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
compact: compact, compact: compact,
} }
if tm, ok := pb.(textMarshaler); ok { if tm, ok := pb.(encoding.TextMarshaler); ok {
text, err := tm.MarshalText() text, err := tm.MarshalText()
if err != nil { if err != nil {
return err return err

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -35,6 +35,7 @@ package proto
// TODO: message sets. // TODO: message sets.
import ( import (
"encoding"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
@ -43,13 +44,6 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// textUnmarshaler is implemented by Messages that can unmarshal themsleves.
// It is identical to encoding.TextUnmarshaler, introduced in go 1.2,
// which will eventually replace it.
type textUnmarshaler interface {
UnmarshalText(text []byte) error
}
type ParseError struct { type ParseError struct {
Message string Message string
Line int // 1-based line number Line int // 1-based line number
@ -361,8 +355,20 @@ func (p *textParser) next() *token {
return &p.cur return &p.cur
} }
// Return an error indicating which required field was not set. func (p *textParser) consumeToken(s string) error {
func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError { 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() st := sv.Type()
sprops := GetProperties(st) sprops := GetProperties(st)
for i := 0; i < st.NumField(); i++ { for i := 0; i < st.NumField(); i++ {
@ -372,10 +378,10 @@ func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError {
props := sprops.Prop[i] props := sprops.Prop[i]
if props.Required { if props.Required {
return p.errorf("message %v missing required field %q", st, props.OrigName) return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)}
} }
} }
return p.errorf("message %v missing required field", st) // should not happen 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. // Returns the index in the struct for the named field, as well as the parsed tag properties.
@ -415,6 +421,10 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr
if typ.Elem().Kind() != reflect.Ptr { if typ.Elem().Kind() != reflect.Ptr {
break break
} }
} else if typ.Kind() == reflect.String {
// The proto3 exception is for a string field,
// which requires a colon.
break
} }
needColon = false needColon = false
} }
@ -426,9 +436,11 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr
return nil return nil
} }
func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError { func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
st := sv.Type() st := sv.Type()
reqCount := GetProperties(st).reqCount reqCount := GetProperties(st).reqCount
var reqFieldErr error
fieldSet := make(map[string]bool)
// A struct is a sequence of "name: value", terminated by one of // A struct is a sequence of "name: value", terminated by one of
// '>' or '}', or the end of the input. A name may also be // '>' or '}', or the end of the input. A name may also be
// "[extension]". // "[extension]".
@ -489,7 +501,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError
ext = reflect.New(typ.Elem()).Elem() ext = reflect.New(typ.Elem()).Elem()
} }
if err := p.readAny(ext, props); err != nil { if err := p.readAny(ext, props); err != nil {
return err if _, ok := err.(*RequiredNotSetError); !ok {
return err
}
reqFieldErr = err
} }
ep := sv.Addr().Interface().(extendableProto) ep := sv.Addr().Interface().(extendableProto)
if !rep { if !rep {
@ -507,17 +522,71 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError
} }
} else { } else {
// This is a normal, non-extension field. // This is a normal, non-extension field.
fi, props, ok := structFieldByName(st, tok.value) name := tok.value
fi, props, ok := structFieldByName(st, name)
if !ok { if !ok {
return p.errorf("unknown field name %q in %v", tok.value, st) return p.errorf("unknown field name %q in %v", name, st)
} }
dst := sv.Field(fi) dst := sv.Field(fi)
isDstNil := isNil(dst)
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. // Check that it's not already set if it's not a repeated field.
if !props.Repeated && !isDstNil { if !props.Repeated && fieldSet[name] {
return p.errorf("non-repeated field %q was repeated", tok.value) return p.errorf("non-repeated field %q was repeated", name)
} }
if err := p.checkForColon(props, st.Field(fi).Type); err != nil { if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
@ -525,11 +594,13 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError
} }
// Parse into the field. // Parse into the field.
fieldSet[name] = true
if err := p.readAny(dst, props); err != nil { if err := p.readAny(dst, props); err != nil {
return err if _, ok := err.(*RequiredNotSetError); !ok {
} return err
}
if props.Required { reqFieldErr = err
} else if props.Required {
reqCount-- reqCount--
} }
} }
@ -547,10 +618,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError
if reqCount > 0 { if reqCount > 0 {
return p.missingRequiredFieldError(sv) return p.missingRequiredFieldError(sv)
} }
return nil return reqFieldErr
} }
func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError { func (p *textParser) readAny(v reflect.Value, props *Properties) error {
tok := p.next() tok := p.next()
if tok.err != nil { if tok.err != nil {
return tok.err return tok.err
@ -652,7 +723,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
default: default:
return p.errorf("expected '{' or '<', found %q", tok.value) return p.errorf("expected '{' or '<', found %q", tok.value)
} }
// TODO: Handle nested messages which implement textUnmarshaler. // TODO: Handle nested messages which implement encoding.TextUnmarshaler.
return p.readStruct(fv, terminator) return p.readStruct(fv, terminator)
case reflect.Uint32: case reflect.Uint32:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
@ -670,8 +741,10 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb // UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
// before starting to unmarshal, so any existing data in pb is always removed. // 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 { func UnmarshalText(s string, pb Message) error {
if um, ok := pb.(textUnmarshaler); ok { if um, ok := pb.(encoding.TextUnmarshaler); ok {
err := um.UnmarshalText([]byte(s)) err := um.UnmarshalText([]byte(s))
return err return err
} }

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -36,8 +36,9 @@ import (
"reflect" "reflect"
"testing" "testing"
proto3pb "./proto3_proto"
. "./testdata" . "./testdata"
. "code.google.com/p/goprotobuf/proto" . "github.com/golang/protobuf/proto"
) )
type UnmarshalTextTest struct { type UnmarshalTextTest struct {
@ -294,8 +295,11 @@ var unMarshalTextTests = []UnmarshalTextTest{
// Missing required field // Missing required field
{ {
in: ``, in: `name: "Pawel"`,
err: `line 1.0: message testdata.MyMessage missing required field "count"`, err: `proto: required field "testdata.MyMessage.count" not set`,
out: &MyMessage{
Name: String("Pawel"),
},
}, },
// Repeated non-repeated field // Repeated non-repeated field
@ -408,6 +412,9 @@ func TestUnmarshalText(t *testing.T) {
} else if err.Error() != test.err { } else if err.Error() != test.err {
t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
i, err.Error(), test.err) 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)
} }
} }
} }
@ -437,6 +444,48 @@ func TestRepeatedEnum(t *testing.T) {
} }
} }
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 var benchInput string
func init() { func init() {

View file

@ -1,7 +1,7 @@
// Go support for Protocol Buffers - Google's data interchange format // Go support for Protocol Buffers - Google's data interchange format
// //
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// http://code.google.com/p/goprotobuf/ // https://github.com/golang/protobuf
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
@ -39,8 +39,9 @@ import (
"strings" "strings"
"testing" "testing"
"code.google.com/p/goprotobuf/proto" "github.com/golang/protobuf/proto"
proto3pb "./proto3_proto"
pb "./testdata" pb "./testdata"
) )
@ -406,3 +407,30 @@ Message <nil>
t.Errorf(" got: %s\nwant: %s", 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)
}
}
}