github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/message_set.go (about) 1 // Go support for Protocol Buffers - Google's data interchange format 2 // 3 // Copyright 2010 The Go Authors. All rights reserved. 4 // http://code.google.com/p/goprotobuf/ 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32 package proto 33 34 /* 35 * Support for message sets. 36 */ 37 38 import ( 39 "errors" 40 "reflect" 41 "sort" 42 ) 43 44 // ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID. 45 // A message type ID is required for storing a protocol buffer in a message set. 46 var ErrNoMessageTypeId = errors.New("proto does not have a message type ID") 47 48 // The first two types (_MessageSet_Item and MessageSet) 49 // model what the protocol compiler produces for the following protocol message: 50 // message MessageSet { 51 // repeated group Item = 1 { 52 // required int32 type_id = 2; 53 // required string message = 3; 54 // }; 55 // } 56 // That is the MessageSet wire format. We can't use a proto to generate these 57 // because that would introduce a circular dependency between it and this package. 58 // 59 // When a proto1 proto has a field that looks like: 60 // optional message<MessageSet> info = 3; 61 // the protocol compiler produces a field in the generated struct that looks like: 62 // Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"` 63 // The package is automatically inserted so there is no need for that proto file to 64 // import this package. 65 66 type _MessageSet_Item struct { 67 TypeId *int32 `protobuf:"varint,2,req,name=type_id"` 68 Message []byte `protobuf:"bytes,3,req,name=message"` 69 } 70 71 type MessageSet struct { 72 Item []*_MessageSet_Item `protobuf:"group,1,rep"` 73 XXX_unrecognized []byte 74 // TODO: caching? 75 } 76 77 // Make sure MessageSet is a Message. 78 var _ Message = (*MessageSet)(nil) 79 80 // messageTypeIder is an interface satisfied by a protocol buffer type 81 // that may be stored in a MessageSet. 82 type messageTypeIder interface { 83 MessageTypeId() int32 84 } 85 86 func (ms *MessageSet) find(pb Message) *_MessageSet_Item { 87 mti, ok := pb.(messageTypeIder) 88 if !ok { 89 return nil 90 } 91 id := mti.MessageTypeId() 92 for _, item := range ms.Item { 93 if *item.TypeId == id { 94 return item 95 } 96 } 97 return nil 98 } 99 100 func (ms *MessageSet) Has(pb Message) bool { 101 if ms.find(pb) != nil { 102 return true 103 } 104 return false 105 } 106 107 func (ms *MessageSet) Unmarshal(pb Message) error { 108 if item := ms.find(pb); item != nil { 109 return Unmarshal(item.Message, pb) 110 } 111 if _, ok := pb.(messageTypeIder); !ok { 112 return ErrNoMessageTypeId 113 } 114 return nil // TODO: return error instead? 115 } 116 117 func (ms *MessageSet) Marshal(pb Message) error { 118 msg, err := Marshal(pb) 119 if err != nil { 120 return err 121 } 122 if item := ms.find(pb); item != nil { 123 // reuse existing item 124 item.Message = msg 125 return nil 126 } 127 128 mti, ok := pb.(messageTypeIder) 129 if !ok { 130 return ErrWrongType // TODO: custom error? 131 } 132 133 mtid := mti.MessageTypeId() 134 ms.Item = append(ms.Item, &_MessageSet_Item{ 135 TypeId: &mtid, 136 Message: msg, 137 }) 138 return nil 139 } 140 141 func (ms *MessageSet) Reset() { *ms = MessageSet{} } 142 func (ms *MessageSet) String() string { return CompactTextString(ms) } 143 func (*MessageSet) ProtoMessage() {} 144 145 // Support for the message_set_wire_format message option. 146 147 func skipVarint(buf []byte) []byte { 148 i := 0 149 for ; buf[i]&0x80 != 0; i++ { 150 } 151 return buf[i+1:] 152 } 153 154 // MarshalMessageSet encodes the extension map represented by m in the message set wire format. 155 // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. 156 func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { 157 if err := encodeExtensionMap(m); err != nil { 158 return nil, err 159 } 160 161 // Sort extension IDs to provide a deterministic encoding. 162 // See also enc_map in encode.go. 163 ids := make([]int, 0, len(m)) 164 for id := range m { 165 ids = append(ids, int(id)) 166 } 167 sort.Ints(ids) 168 169 ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))} 170 for _, id := range ids { 171 e := m[int32(id)] 172 // Remove the wire type and field number varint, as well as the length varint. 173 msg := skipVarint(skipVarint(e.enc)) 174 175 ms.Item = append(ms.Item, &_MessageSet_Item{ 176 TypeId: Int32(int32(id)), 177 Message: msg, 178 }) 179 } 180 return Marshal(ms) 181 } 182 183 // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. 184 // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. 185 func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { 186 ms := new(MessageSet) 187 if err := Unmarshal(buf, ms); err != nil { 188 return err 189 } 190 for _, item := range ms.Item { 191 // restore wire type and field number varint, plus length varint. 192 b := EncodeVarint(uint64(*item.TypeId)<<3 | WireBytes) 193 b = append(b, EncodeVarint(uint64(len(item.Message)))...) 194 b = append(b, item.Message...) 195 196 m[*item.TypeId] = Extension{enc: b} 197 } 198 return nil 199 } 200 201 // A global registry of types that can be used in a MessageSet. 202 203 var messageSetMap = make(map[int32]messageSetDesc) 204 205 type messageSetDesc struct { 206 t reflect.Type // pointer to struct 207 name string 208 } 209 210 // RegisterMessageSetType is called from the generated code. 211 func RegisterMessageSetType(i messageTypeIder, name string) { 212 messageSetMap[i.MessageTypeId()] = messageSetDesc{ 213 t: reflect.TypeOf(i), 214 name: name, 215 } 216 }