From 740a99a9accb7796355814acb8468dc49ce73429 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Sun, 15 Feb 2015 13:54:43 +0100 Subject: [PATCH] Remove Google Code files, add GitHub files for protobuf lib. --- .../golang/protobuf}/proto/Makefile | 7 +- .../golang/protobuf}/proto/all_test.go | 84 +++++- .../golang/protobuf}/proto/clone.go | 38 ++- .../golang/protobuf}/proto/clone_test.go | 45 ++- .../golang/protobuf}/proto/decode.go | 112 +++++++- .../golang/protobuf}/proto/encode.go | 261 ++++++++++++++++-- .../golang/protobuf}/proto/equal.go | 19 +- .../golang/protobuf}/proto/equal_test.go | 29 +- .../golang/protobuf}/proto/extensions.go | 6 +- .../golang/protobuf/proto/extensions_test.go | 137 +++++++++ .../golang/protobuf}/proto/lib.go | 91 +++--- .../golang/protobuf}/proto/message_set.go | 66 ++++- .../protobuf}/proto/message_set_test.go | 2 +- .../golang/protobuf}/proto/pointer_reflect.go | 99 ++++++- .../golang/protobuf}/proto/pointer_unsafe.go | 52 +++- .../golang/protobuf}/proto/properties.go | 76 ++++- .../protobuf/proto/proto3_proto/Makefile | 44 +++ .../protobuf/proto/proto3_proto/proto3.proto} | 50 ++-- .../golang/protobuf/proto/proto3_test.go | 93 +++++++ .../golang/protobuf}/proto/size2_test.go | 2 +- .../golang/protobuf}/proto/size_test.go | 19 +- .../golang/protobuf}/proto/testdata/Makefile | 6 +- .../protobuf}/proto/testdata/golden_test.go | 2 +- .../protobuf}/proto/testdata/test.pb.go | 41 ++- .../protobuf}/proto/testdata/test.proto | 8 +- .../golang/protobuf}/proto/text.go | 108 +++++++- .../golang/protobuf}/proto/text_parser.go | 127 +++++++-- .../protobuf}/proto/text_parser_test.go | 57 +++- .../golang/protobuf}/proto/text_test.go | 32 ++- 29 files changed, 1546 insertions(+), 167 deletions(-) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/Makefile (94%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/all_test.go (96%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/clone.go (83%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/clone_test.go (78%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/decode.go (85%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/encode.go (78%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/equal.go (94%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/equal_test.go (90%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/extensions.go (98%) create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/lib.go (89%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/message_set.go (79%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/message_set_test.go (98%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/pointer_reflect.go (82%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/pointer_unsafe.go (84%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/properties.go (88%) create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile rename Godeps/_workspace/src/{code.google.com/p/goprotobuf/proto/extensions_test.go => github.com/golang/protobuf/proto/proto3_proto/proto3.proto} (69%) create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/size2_test.go (98%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/size_test.go (83%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/testdata/Makefile (96%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/testdata/golden_test.go (98%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/testdata/test.pb.go (97%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/testdata/test.proto (98%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/text.go (87%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/text_parser.go (84%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/text_parser_test.go (87%) rename Godeps/_workspace/src/{code.google.com/p/goprotobuf => github.com/golang/protobuf}/proto/text_test.go (92%) diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/Makefile b/Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile similarity index 94% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/Makefile rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile index e99b839a7d..fb838ed2d7 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/Makefile +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile @@ -1,7 +1,7 @@ # Go support for Protocol Buffers - Google's data interchange format # # 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 # modification, are permitted provided that the following conditions are @@ -37,4 +37,7 @@ test: install generate-test-pbs generate-test-pbs: - make install && cd testdata && make + make install + make -C testdata + make -C proto3_proto + make diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/all_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go similarity index 96% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/all_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go index b2a0191fcd..3fade175f7 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/all_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -45,7 +45,7 @@ import ( "time" . "./testdata" - . "code.google.com/p/goprotobuf/proto" + . "github.com/golang/protobuf/proto" ) var globalO *Buffer @@ -1833,6 +1833,86 @@ func fuzzUnmarshal(t *testing.T, data []byte) { 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 func testMsg() *GoTest { diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go similarity index 83% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go index 8b94d9e186..6c6a7d95f2 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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 // 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. package proto @@ -113,6 +113,29 @@ func mergeAny(out, in reflect.Value) { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: out.Set(in) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key)) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } case reflect.Ptr: if in.IsNil() { return @@ -125,6 +148,14 @@ func mergeAny(out, in reflect.Value) { if in.IsNil() { return } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } n := in.Len() if out.IsNil() { out.Set(reflect.MakeSlice(in.Type(), 0, n)) @@ -133,9 +164,6 @@ func mergeAny(out, in reflect.Value) { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: out.Set(reflect.AppendSlice(out, in)) - case reflect.Uint8: - // []byte is a scalar bytes field. - out.Set(in) default: for i := 0; i < n; i++ { x := reflect.Indirect(reflect.New(in.Type().Elem())) diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go similarity index 78% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go index 39aaaf7bda..1ac177d216 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/clone_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -34,7 +34,7 @@ package proto_test import ( "testing" - "code.google.com/p/goprotobuf/proto" + "github.com/golang/protobuf/proto" pb "./testdata" ) @@ -79,6 +79,22 @@ func TestClone(t *testing.T) { if proto.Equal(m, cloneTestMessage) { t.Error("Mutating clone changed the original") } + // Byte fields and repeated fields should be copied. + if &m.Pet[0] == &cloneTestMessage.Pet[0] { + t.Error("Pet: repeated field not copied") + } + if &m.Others[0] == &cloneTestMessage.Others[0] { + t.Error("Others: repeated field not copied") + } + if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { + t.Error("Others[0].Value: bytes field not copied") + } + if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { + t.Error("RepBytes: repeated field not copied") + } + if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { + t.Error("RepBytes[0]: bytes field not copied") + } } func TestCloneNil(t *testing.T) { @@ -173,6 +189,31 @@ var mergeTests = []struct { dst: &pb.OtherMessage{Value: []byte("bar")}, want: &pb.OtherMessage{Value: []byte("foo")}, }, + { + src: &pb.MessageWithMap{ + NameMapping: map[int32]string{6: "Nigel"}, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + dst: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Bruce", // should be overwritten + 7: "Andrew", + }, + }, + want: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Nigel", + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + }, } func TestMerge(t *testing.T) { diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/decode.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go similarity index 85% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/decode.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go index 49a487a375..129792ed12 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/decode.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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) { n, err := p.DecodeVarint() if err != nil { - return + return nil, err } nb := int(n) @@ -362,7 +362,7 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group } tag := int(u >> 3) 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) if !ok { @@ -465,6 +465,15 @@ func (o *Buffer) dec_bool(p *Properties, base structPointer) error { return nil } +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + // Decode an int32. func (o *Buffer) dec_int32(p *Properties, base structPointer) error { u, err := p.valDec(o) @@ -475,6 +484,15 @@ func (o *Buffer) dec_int32(p *Properties, base structPointer) error { return nil } +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + // Decode an int64. func (o *Buffer) dec_int64(p *Properties, base structPointer) error { u, err := p.valDec(o) @@ -485,15 +503,31 @@ func (o *Buffer) dec_int64(p *Properties, base structPointer) error { return nil } +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + // Decode a string. func (o *Buffer) dec_string(p *Properties, base structPointer) error { s, err := o.DecodeStringBytes() if err != nil { return err } - sp := new(string) - *sp = s - *structPointer_String(base, p.field) = sp + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s return nil } @@ -632,6 +666,72 @@ func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { return nil } +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_Map(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + + v.SetMapIndex(keyptr.Elem(), valptr.Elem()) + return nil +} + // Decode a group. func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { bas := structPointer_GetStructPointer(base, p.field) diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/encode.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go similarity index 78% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/encode.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go index 35e5ad56ef..1512d605b2 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/encode.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -247,7 +247,7 @@ func (p *Buffer) Marshal(pb Message) error { return ErrNil } if err == nil { - err = p.enc_struct(t.Elem(), GetProperties(t.Elem()), base) + err = p.enc_struct(GetProperties(t.Elem()), base) } if collectStats { @@ -271,7 +271,7 @@ func Size(pb Message) (n int) { return 0 } if err == nil { - n = size_struct(t.Elem(), GetProperties(t.Elem()), base) + n = size_struct(GetProperties(t.Elem()), base) } if collectStats { @@ -298,6 +298,16 @@ func (o *Buffer) enc_bool(p *Properties, base structPointer) error { return nil } +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + func size_bool(p *Properties, base structPointer) int { v := *structPointer_Bool(base, p.field) if v == nil { @@ -306,6 +316,14 @@ func size_bool(p *Properties, base structPointer) int { 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. func (o *Buffer) enc_int32(p *Properties, base structPointer) error { v := structPointer_Word32(base, p.field) @@ -318,6 +336,17 @@ func (o *Buffer) enc_int32(p *Properties, base structPointer) error { return nil } +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + func size_int32(p *Properties, base structPointer) (n int) { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { @@ -329,6 +358,17 @@ func size_int32(p *Properties, base structPointer) (n int) { 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. // Exactly the same as int32, except for no sign extension. 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 } +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + func size_uint32(p *Properties, base structPointer) (n int) { v := structPointer_Word32(base, p.field) if word32_IsNil(v) { @@ -353,6 +404,17 @@ func size_uint32(p *Properties, base structPointer) (n int) { 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. func (o *Buffer) enc_int64(p *Properties, base structPointer) error { v := structPointer_Word64(base, p.field) @@ -365,6 +427,17 @@ func (o *Buffer) enc_int64(p *Properties, base structPointer) error { return nil } +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + func size_int64(p *Properties, base structPointer) (n int) { v := structPointer_Word64(base, p.field) if word64_IsNil(v) { @@ -376,6 +449,17 @@ func size_int64(p *Properties, base structPointer) (n int) { 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. func (o *Buffer) enc_string(p *Properties, base structPointer) error { v := *structPointer_String(base, p.field) @@ -388,6 +472,16 @@ func (o *Buffer) enc_string(p *Properties, base structPointer) error { return nil } +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + func size_string(p *Properties, base structPointer) (n int) { v := *structPointer_String(base, p.field) if v == nil { @@ -399,6 +493,16 @@ func size_string(p *Properties, base structPointer) (n int) { 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. func isNil(v reflect.Value) bool { 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...) - 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 { @@ -448,7 +552,7 @@ func size_struct_message(p *Properties, base structPointer) int { } 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 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)) - err := o.enc_struct(p.stype, p.sprop, b) + err := o.enc_struct(p.sprop, b) if err != nil && !state.shouldContinue(err, nil) { return err } @@ -477,7 +581,7 @@ func size_struct_group(p *Properties, base structPointer) (n int) { } 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)) return } @@ -551,6 +655,16 @@ func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { return nil } +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + func size_slice_byte(p *Properties, base structPointer) (n int) { s := *structPointer_Bytes(base, p.field) if s == nil { @@ -561,6 +675,16 @@ func size_slice_byte(p *Properties, base structPointer) (n int) { 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). func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { 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...) - 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 == ErrNil { return ErrRepeatedHasNil @@ -861,7 +985,7 @@ func size_slice_struct_message(p *Properties, base structPointer) (n int) { continue } - n0 := size_struct(p.stype, p.sprop, structp) + n0 := size_struct(p.sprop, structp) n1 := sizeVarint(uint64(n0)) // size of encoded length 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)) - 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 == ErrNil { @@ -908,7 +1032,7 @@ func size_slice_struct_group(p *Properties, base structPointer) (n int) { return // return size up to this point } - n += size_struct(p.stype, p.sprop, b) + n += size_struct(p.sprop, b) } return } @@ -945,12 +1069,112 @@ func size_map(p *Properties, base structPointer) int { 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 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. -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 // Encode fields in tag order so that decoders may use optimizations // 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 { p := prop.Prop[i] if p.enc != nil { @@ -978,7 +1202,7 @@ func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structP 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 { p := prop.Prop[i] 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 // 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) o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length iMsg := len(o.buf) - err := o.enc_struct(t, prop, base) + err := enc() if err != nil && !state.shouldContinue(err, nil) { return err } diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go similarity index 94% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go index 42542e6928..d8673a3e97 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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) - Two unset fields are equal. - 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 elements that are pairwise 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() case reflect.Int32, reflect.Int64: return v1.Int() == v2.Int() + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2) { + return false + } + } + return true case reflect.Ptr: return equalAny(v1.Elem(), v2.Elem()) case reflect.Slice: diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go similarity index 90% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go index cdf3fd9c24..cc25833ca4 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/equal_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -35,7 +35,7 @@ import ( "testing" pb "./testdata" - . "code.google.com/p/goprotobuf/proto" + . "github.com/golang/protobuf/proto" ) // Four identical base messages. @@ -155,6 +155,31 @@ var EqualTests = []struct { }, 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) { diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go similarity index 98% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go index e592053c51..f7667fab48 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -227,7 +227,8 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er return nil, err } - e, ok := pb.ExtensionMap()[extension.Field] + emap := pb.ExtensionMap() + e, ok := emap[extension.Field] if !ok { return nil, ErrMissingExtension } @@ -252,6 +253,7 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er e.value = v e.desc = extension e.enc = nil + emap[extension.Field] = e return e.value, nil } diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go new file mode 100644 index 0000000000..451ad871a2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go @@ -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") + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/lib.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go similarity index 89% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/lib.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go index 46a4416fdf..f81052f2ae 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/lib.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -39,7 +39,7 @@ - Names are turned from camel_case to CamelCase for export. - There are no methods on v to set fields; just treat - them as structure fields. + them as structure fields. - There are getters that return a field's value if set, and return the field's default value if unset. The getters work even if the receiver is a nil message. @@ -50,17 +50,16 @@ That is, optional or required field int32 f becomes F *int32. - Repeated fields are slices. - Helper functions are available to aid the setting of fields. - Helpers for getting values are superseded by the - GetFoo methods and their use is deprecated. - msg.Foo = proto.String("hello") // set field + msg.Foo = proto.String("hello") // set field - Constants are defined to hold the default values of all fields that have them. They have the form Default_StructName_FieldName. Because the getter methods handle defaulted values, direct use of these constants should be rare. - Enums are given type names and maps from names to values. - Enum values are prefixed with the enum's type name. Enum types have - a String method, and a Enum method to assist in message construction. - - Nested groups and enums have type names prefixed with the name of + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of the surrounding message type. - Extensions are given descriptor names that start with E_, followed by an underscore-delimited list of the nested messages @@ -74,7 +73,7 @@ package example; - enum FOO { X = 17; }; + enum FOO { X = 17; } message Test { required string label = 1; @@ -89,7 +88,8 @@ package example - import "code.google.com/p/goprotobuf/proto" + import proto "github.com/golang/protobuf/proto" + import math "math" type FOO int32 const ( @@ -110,6 +110,14 @@ func (x FOO) String() string { return proto.EnumName(FOO_name, int32(x)) } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } type Test struct { Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` @@ -118,41 +126,41 @@ Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` XXX_unrecognized []byte `json:"-"` } - func (this *Test) Reset() { *this = Test{} } - func (this *Test) String() string { return proto.CompactTextString(this) } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} const Default_Test_Type int32 = 77 - func (this *Test) GetLabel() string { - if this != nil && this.Label != nil { - return *this.Label + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label } return "" } - func (this *Test) GetType() int32 { - if this != nil && this.Type != nil { - return *this.Type + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type } return Default_Test_Type } - func (this *Test) GetOptionalgroup() *Test_OptionalGroup { - if this != nil { - return this.Optionalgroup + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup } return nil } type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` - XXX_unrecognized []byte `json:"-"` + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` } - func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} } - func (this *Test_OptionalGroup) String() string { return proto.CompactTextString(this) } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - func (this *Test_OptionalGroup) GetRequiredField() string { - if this != nil && this.RequiredField != nil { - return *this.RequiredField + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField } return "" } @@ -168,15 +176,15 @@ import ( "log" - "code.google.com/p/goprotobuf/proto" - "./example.pb" + "github.com/golang/protobuf/proto" + pb "./example.pb" ) func main() { - test := &example.Test{ + test := &pb.Test{ Label: proto.String("hello"), Type: proto.Int32(17), - Optionalgroup: &example.Test_OptionalGroup{ + Optionalgroup: &pb.Test_OptionalGroup{ RequiredField: proto.String("good bye"), }, } @@ -184,7 +192,7 @@ if err != nil { log.Fatal("marshaling error: ", err) } - newTest := new(example.Test) + newTest := &pb.Test{} err = proto.Unmarshal(data, newTest) if err != nil { 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 // to store v and returns a pointer to it. func Uint32(v uint32) *uint32 { - p := new(uint32) - *p = v - return p + return &v } // Uint64 is a helper routine that allocates a new uint64 value @@ -738,3 +744,16 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { 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()) +} diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go similarity index 79% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go index 1a17809830..9d912bce19 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -36,7 +36,10 @@ package proto */ import ( + "bytes" + "encoding/json" "errors" + "fmt" "reflect" "sort" ) @@ -211,6 +214,61 @@ func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { return nil } +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + // A global registry of types that can be used in a MessageSet. var messageSetMap = make(map[int32]messageSetDesc) @@ -221,9 +279,9 @@ type messageSetDesc struct { } // RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(i messageTypeIder, name string) { - messageSetMap[i.MessageTypeId()] = messageSetDesc{ - t: reflect.TypeOf(i), +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), name: name, } } diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go similarity index 98% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go index bb311bcccf..7c29bccf4b 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/message_set_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_reflect.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go similarity index 82% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_reflect.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go index 61141ba858..c68b12525c 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_reflect.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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 // 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. // 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) } +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + // BoolSlice returns the address of a []bool field in the struct. func structPointer_BoolSlice(p structPointer, f field) *[]bool { return structPointer_ifield(p, f).(*[]bool) @@ -124,6 +129,11 @@ func structPointer_String(p structPointer, f field) **string { return structPointer_ifield(p, f).(**string) } +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + // StringSlice returns the address of a []string field in the struct. func structPointer_StringSlice(p structPointer, f field) *[]string { return structPointer_ifield(p, f).(*[]string) @@ -134,6 +144,11 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return structPointer_ifield(p, f).(*map[int32]Extension) } +// Map returns the reflect.Value for the address of a map field in the struct. +func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + // SetStructPointer writes a *struct field in the struct. func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { structPointer_field(p, f).Set(q.v) @@ -235,6 +250,49 @@ func structPointer_Word32(p structPointer, f field) word32 { return word32{structPointer_field(p, f)} } +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + // A word32Slice is a slice of 32-bit values. // That is, v.Type() is []int32, []uint32, []float32, or []enum. type word32Slice struct { @@ -339,6 +397,43 @@ func structPointer_Word64(p structPointer, f field) word64 { return word64{structPointer_field(p, f)} } +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + type word64Slice struct { v reflect.Value } diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_unsafe.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go similarity index 84% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_unsafe.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go index 27a536c88d..48bc0fa482 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/pointer_unsafe.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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 // 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. @@ -100,6 +100,11 @@ func structPointer_Bool(p structPointer, f field) **bool { return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) } +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + // BoolSlice returns the address of a []bool field in the struct. func structPointer_BoolSlice(p structPointer, f field) *[]bool { return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) @@ -110,6 +115,11 @@ func structPointer_String(p structPointer, f field) **string { return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) } +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + // StringSlice returns the address of a []string field in the struct. func structPointer_StringSlice(p structPointer, f field) *[]string { return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) @@ -120,6 +130,11 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) } +// Map returns the reflect.Value for the address of a map field in the struct. +func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + // SetStructPointer writes a *struct field in the struct. func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q @@ -170,6 +185,24 @@ func structPointer_Word32(p structPointer, f field) word32 { return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + // A word32Slice is a slice of 32-bit values. type word32Slice []uint32 @@ -206,6 +239,21 @@ func structPointer_Word64(p structPointer, f field) word64 { return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) } +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + // word64Slice is like word32Slice but for 64-bit values. type word64Slice []uint64 diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/properties.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go similarity index 88% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/properties.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go index f2c1e861cd..730a595797 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/properties.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -155,6 +155,7 @@ type Properties struct { Repeated bool Packed bool // relevant for repeated primitives only Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only Default string // default value HasDefault bool // whether an explicit default was provided @@ -170,6 +171,10 @@ type Properties struct { isMarshaler bool isUnmarshaler bool + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + size sizer valSize valueSizer // set for bool and numeric types only @@ -200,6 +205,9 @@ func (p *Properties) String() string { if p.OrigName != p.Name { s += ",name=" + p.OrigName } + if p.proto3 { + s += ",proto3" + } if len(p.Enum) > 0 { s += ",enum=" + p.Enum } @@ -274,6 +282,8 @@ func (p *Properties) Parse(s string) { p.OrigName = f[5:] case strings.HasPrefix(f, "enum="): p.Enum = f[5:] + case f == "proto3": + p.proto3 = true case strings.HasPrefix(f, "def="): p.HasDefault = true p.Default = f[4:] // rest of string @@ -293,19 +303,50 @@ func logNoSliceEnc(t1, t2 reflect.Type) { var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() // 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.dec = nil p.size = nil switch t1 := typ; t1.Kind() { 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: switch t2 := t1.Elem(); t2.Kind() { 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 case reflect.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.dec = (*Buffer).dec_slice_byte p.size = size_slice_byte + if p.proto3 { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } case reflect.Float32, reflect.Float64: switch t2.Bits() { case 32: @@ -461,6 +506,23 @@ func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) { 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 @@ -529,7 +591,7 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF return } p.Parse(tag) - p.setEncAndDec(typ, lockGetProp) + p.setEncAndDec(typ, f, lockGetProp) } var ( @@ -538,7 +600,11 @@ var ( ) // GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } mutex.Lock() sprop := getPropertiesLocked(t) mutex.Unlock() diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile new file mode 100644 index 0000000000..75144b582e --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/Makefile @@ -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 diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto similarity index 69% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto index 03f756b6f8..3e327ded1d 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/extensions_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // 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 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package proto_test +syntax = "proto3"; -import ( - "testing" +package proto3_proto; - pb "./testdata" - "code.google.com/p/goprotobuf/proto" -) +message Message { + enum Humour { + UNKNOWN = 0; + PUNS = 1; + SLAPSTICK = 2; + BILL_BAILEY = 3; + } -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]) - } + string name = 1; + Humour hilarity = 2; + uint32 height_in_cm = 3; + bytes data = 4; + int64 result_count = 7; + bool true_scotsman = 8; + float score = 9; + + repeated uint64 key = 5; + Nested nested = 6; +} + +message Nested { + string bunny = 1; } diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go new file mode 100644 index 0000000000..d4c96a9e73 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go @@ -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) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size2_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go similarity index 98% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size2_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go index 55902a4a9c..a2729c39a1 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size2_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go similarity index 83% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go index 6cb9de6d1d..e5f92d6b90 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/size_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -35,8 +35,9 @@ import ( "log" "testing" + proto3pb "./proto3_proto" pb "./testdata" - . "code.google.com/p/goprotobuf/proto" + . "github.com/golang/protobuf/proto" ) var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} @@ -102,6 +103,20 @@ var SizeTests = []struct { {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, {"extension (unencoded)", messageWithExtension1}, {"extension (encoded)", messageWithExtension3}, + // proto3 message + {"proto3 empty", &proto3pb.Message{}}, + {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, + {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, + {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, + {"proto3 float", &proto3pb.Message{Score: 12.6}}, + {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, + {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, + {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, + {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, + + {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, + {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}}, + {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, } func TestSize(t *testing.T) { diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/Makefile b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile similarity index 96% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/Makefile rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile index 9fa10e4c69..fc288628a7 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/Makefile +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile @@ -1,7 +1,7 @@ # Go support for Protocol Buffers - Google's data interchange format # # 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 # modification, are permitted provided that the following conditions are @@ -37,11 +37,11 @@ all: regenerate regenerate: rm -f test.pb.go make test.pb.go - + # The following rules are just aids to development. Not needed for typical testing. diff: regenerate - hg diff test.pb.go + git diff test.pb.go restore: cp test.pb.go.golden test.pb.go diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/golden_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go similarity index 98% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/golden_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go index f614aa1b73..7172d0e969 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/golden_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.pb.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go similarity index 97% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.pb.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go index 5a9a603662..f47d9e0e39 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.pb.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go @@ -33,10 +33,11 @@ It has these top-level messages: GroupOld GroupNew FloatingPoint + MessageWithMap */ package testdata -import proto "code.google.com/p/goprotobuf/proto" +import proto "github.com/golang/protobuf/proto" import math "math" // 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 { 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 var _ proto.Marshaler = (*MyMessageSet)(nil) @@ -1879,6 +1886,38 @@ func (m *FloatingPoint) GetF() float64 { 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{ ExtendedType: (*MyMessage)(nil), ExtensionType: ([]string)(nil), diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.proto b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto similarity index 98% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.proto rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto index 9c0c4c8970..6cc755baef 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/testdata/test.proto +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -426,3 +426,9 @@ message GroupNew { message FloatingPoint { required double f = 1; } + +message MessageWithMap { + map name_mapping = 1; + map msg_mapping = 2; + map byte_mapping = 3; +} diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go similarity index 87% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go index 5063009c27..720eac4705 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -36,6 +36,7 @@ package proto import ( "bufio" "bytes" + "encoding" "fmt" "io" "log" @@ -74,13 +75,6 @@ type textWriter struct { 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) { if !strings.Contains(s, "\n") { if !w.compact && w.complete { @@ -250,6 +244,100 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } continue } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() // TODO: should we sort these for deterministic output? + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + switch fv.Kind() { + case reflect.Bool: + if !fv.Bool() { + continue + } + case reflect.Int32, reflect.Int64: + if fv.Int() == 0 { + continue + } + case reflect.Uint32, reflect.Uint64: + if fv.Uint() == 0 { + continue + } + case reflect.Float32, reflect.Float64: + if fv.Float() == 0 { + continue + } + case reflect.String: + if fv.String() == "" { + continue + } + } + } if err := writeName(w, props); err != nil { return err @@ -358,7 +446,7 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error { } } w.indent() - if tm, ok := v.Interface().(textMarshaler); ok { + if tm, ok := v.Interface().(encoding.TextMarshaler); ok { text, err := tm.MarshalText() if err != nil { return err @@ -653,7 +741,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error { compact: compact, } - if tm, ok := pb.(textMarshaler); ok { + if tm, ok := pb.(encoding.TextMarshaler); ok { text, err := tm.MarshalText() if err != nil { return err diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go similarity index 84% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go index d235ca9bc8..d1caeff5d9 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -35,6 +35,7 @@ package proto // TODO: message sets. import ( + "encoding" "errors" "fmt" "reflect" @@ -43,13 +44,6 @@ import ( "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 { Message string Line int // 1-based line number @@ -361,8 +355,20 @@ func (p *textParser) next() *token { return &p.cur } -// Return an error indicating which required field was not set. -func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError { +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { st := sv.Type() sprops := GetProperties(st) for i := 0; i < st.NumField(); i++ { @@ -372,10 +378,10 @@ func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError { props := sprops.Prop[i] 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.", st)} // should not happen } // 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 { break } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break } needColon = false } @@ -426,9 +436,11 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr 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() reqCount := GetProperties(st).reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) // A struct is a sequence of "name: value", terminated by one of // '>' or '}', or the end of the input. A name may also be // "[extension]". @@ -489,7 +501,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError ext = reflect.New(typ.Elem()).Elem() } if err := p.readAny(ext, props); err != nil { - return err + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err } ep := sv.Addr().Interface().(extendableProto) if !rep { @@ -507,17 +522,71 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError } } else { // 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 { - 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) - 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. - if !props.Repeated && !isDstNil { - return p.errorf("non-repeated field %q was repeated", tok.value) + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) } if err := p.checkForColon(props, st.Field(fi).Type); err != nil { @@ -525,11 +594,13 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError } // Parse into the field. + fieldSet[name] = true if err := p.readAny(dst, props); err != nil { - return err - } - - if props.Required { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } else if props.Required { reqCount-- } } @@ -547,10 +618,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError if reqCount > 0 { 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() if tok.err != nil { return tok.err @@ -652,7 +723,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError { default: 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) case reflect.Uint32: 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 // before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { - if um, ok := pb.(textUnmarshaler); ok { + if um, ok := pb.(encoding.TextUnmarshaler); ok { err := um.UnmarshalText([]byte(s)) return err } diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go similarity index 87% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go index d043769ec1..1360e8e8b7 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_parser_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -36,8 +36,9 @@ import ( "reflect" "testing" + proto3pb "./proto3_proto" . "./testdata" - . "code.google.com/p/goprotobuf/proto" + . "github.com/golang/protobuf/proto" ) type UnmarshalTextTest struct { @@ -294,8 +295,11 @@ var unMarshalTextTests = []UnmarshalTextTest{ // Missing required field { - in: ``, - err: `line 1.0: message testdata.MyMessage missing required field "count"`, + in: `name: "Pawel"`, + err: `proto: required field "testdata.MyMessage.count" not set`, + out: &MyMessage{ + Name: String("Pawel"), + }, }, // Repeated non-repeated field @@ -408,6 +412,9 @@ func TestUnmarshalText(t *testing.T) { } else if err.Error() != test.err { t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", i, err.Error(), test.err) + } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) } } } @@ -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: name_mapping:` + + `msg_mapping:>` + + `msg_mapping>` + // no colon after "value" + `byte_mapping:` + want := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Beatles", + 1234: "Feist", + }, + MsgMapping: map[int64]*FloatingPoint{ + -4: {F: Float64(2.0)}, + -2: {F: Float64(4.0)}, + }, + ByteMapping: map[bool][]byte{ + true: []byte("so be it"), + }, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + var benchInput string func init() { diff --git a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go similarity index 92% rename from Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_test.go rename to Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go index 224a484e50..707bedd000 100644 --- a/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto/text_test.go +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go @@ -1,7 +1,7 @@ // Go support for Protocol Buffers - Google's data interchange format // // 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 // modification, are permitted provided that the following conditions are @@ -39,8 +39,9 @@ import ( "strings" "testing" - "code.google.com/p/goprotobuf/proto" + "github.com/golang/protobuf/proto" + proto3pb "./proto3_proto" pb "./testdata" ) @@ -406,3 +407,30 @@ Message 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:`, + }, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +}