message_set.go

  1// Go support for Protocol Buffers - Google's data interchange format
  2//
  3// Copyright 2010 The Go Authors.  All rights reserved.
  4// https://github.com/golang/protobuf
  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
 32package proto
 33
 34/*
 35 * Support for message sets.
 36 */
 37
 38import (
 39	"bytes"
 40	"encoding/json"
 41	"errors"
 42	"fmt"
 43	"reflect"
 44	"sort"
 45	"sync"
 46)
 47
 48// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
 49// A message type ID is required for storing a protocol buffer in a message set.
 50var errNoMessageTypeID = errors.New("proto does not have a message type ID")
 51
 52// The first two types (_MessageSet_Item and messageSet)
 53// model what the protocol compiler produces for the following protocol message:
 54//   message MessageSet {
 55//     repeated group Item = 1 {
 56//       required int32 type_id = 2;
 57//       required string message = 3;
 58//     };
 59//   }
 60// That is the MessageSet wire format. We can't use a proto to generate these
 61// because that would introduce a circular dependency between it and this package.
 62
 63type _MessageSet_Item struct {
 64	TypeId  *int32 `protobuf:"varint,2,req,name=type_id"`
 65	Message []byte `protobuf:"bytes,3,req,name=message"`
 66}
 67
 68type messageSet struct {
 69	Item             []*_MessageSet_Item `protobuf:"group,1,rep"`
 70	XXX_unrecognized []byte
 71	// TODO: caching?
 72}
 73
 74// Make sure messageSet is a Message.
 75var _ Message = (*messageSet)(nil)
 76
 77// messageTypeIder is an interface satisfied by a protocol buffer type
 78// that may be stored in a MessageSet.
 79type messageTypeIder interface {
 80	MessageTypeId() int32
 81}
 82
 83func (ms *messageSet) find(pb Message) *_MessageSet_Item {
 84	mti, ok := pb.(messageTypeIder)
 85	if !ok {
 86		return nil
 87	}
 88	id := mti.MessageTypeId()
 89	for _, item := range ms.Item {
 90		if *item.TypeId == id {
 91			return item
 92		}
 93	}
 94	return nil
 95}
 96
 97func (ms *messageSet) Has(pb Message) bool {
 98	return ms.find(pb) != nil
 99}
100
101func (ms *messageSet) Unmarshal(pb Message) error {
102	if item := ms.find(pb); item != nil {
103		return Unmarshal(item.Message, pb)
104	}
105	if _, ok := pb.(messageTypeIder); !ok {
106		return errNoMessageTypeID
107	}
108	return nil // TODO: return error instead?
109}
110
111func (ms *messageSet) Marshal(pb Message) error {
112	msg, err := Marshal(pb)
113	if err != nil {
114		return err
115	}
116	if item := ms.find(pb); item != nil {
117		// reuse existing item
118		item.Message = msg
119		return nil
120	}
121
122	mti, ok := pb.(messageTypeIder)
123	if !ok {
124		return errNoMessageTypeID
125	}
126
127	mtid := mti.MessageTypeId()
128	ms.Item = append(ms.Item, &_MessageSet_Item{
129		TypeId:  &mtid,
130		Message: msg,
131	})
132	return nil
133}
134
135func (ms *messageSet) Reset()         { *ms = messageSet{} }
136func (ms *messageSet) String() string { return CompactTextString(ms) }
137func (*messageSet) ProtoMessage()     {}
138
139// Support for the message_set_wire_format message option.
140
141func skipVarint(buf []byte) []byte {
142	i := 0
143	for ; buf[i]&0x80 != 0; i++ {
144	}
145	return buf[i+1:]
146}
147
148// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
149// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
150func MarshalMessageSet(exts interface{}) ([]byte, error) {
151	return marshalMessageSet(exts, false)
152}
153
154// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
155func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
156	switch exts := exts.(type) {
157	case *XXX_InternalExtensions:
158		var u marshalInfo
159		siz := u.sizeMessageSet(exts)
160		b := make([]byte, 0, siz)
161		return u.appendMessageSet(b, exts, deterministic)
162
163	case map[int32]Extension:
164		// This is an old-style extension map.
165		// Wrap it in a new-style XXX_InternalExtensions.
166		ie := XXX_InternalExtensions{
167			p: &struct {
168				mu           sync.Mutex
169				extensionMap map[int32]Extension
170			}{
171				extensionMap: exts,
172			},
173		}
174
175		var u marshalInfo
176		siz := u.sizeMessageSet(&ie)
177		b := make([]byte, 0, siz)
178		return u.appendMessageSet(b, &ie, deterministic)
179
180	default:
181		return nil, errors.New("proto: not an extension map")
182	}
183}
184
185// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
186// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
187func UnmarshalMessageSet(buf []byte, exts interface{}) error {
188	var m map[int32]Extension
189	switch exts := exts.(type) {
190	case *XXX_InternalExtensions:
191		m = exts.extensionsWrite()
192	case map[int32]Extension:
193		m = exts
194	default:
195		return errors.New("proto: not an extension map")
196	}
197
198	ms := new(messageSet)
199	if err := Unmarshal(buf, ms); err != nil {
200		return err
201	}
202	for _, item := range ms.Item {
203		id := *item.TypeId
204		msg := item.Message
205
206		// Restore wire type and field number varint, plus length varint.
207		// Be careful to preserve duplicate items.
208		b := EncodeVarint(uint64(id)<<3 | WireBytes)
209		if ext, ok := m[id]; ok {
210			// Existing data; rip off the tag and length varint
211			// so we join the new data correctly.
212			// We can assume that ext.enc is set because we are unmarshaling.
213			o := ext.enc[len(b):]   // skip wire type and field number
214			_, n := DecodeVarint(o) // calculate length of length varint
215			o = o[n:]               // skip length varint
216			msg = append(o, msg...) // join old data and new data
217		}
218		b = append(b, EncodeVarint(uint64(len(msg)))...)
219		b = append(b, msg...)
220
221		m[id] = Extension{enc: b}
222	}
223	return nil
224}
225
226// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
227// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
228func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
229	var m map[int32]Extension
230	switch exts := exts.(type) {
231	case *XXX_InternalExtensions:
232		var mu sync.Locker
233		m, mu = exts.extensionsRead()
234		if m != nil {
235			// Keep the extensions map locked until we're done marshaling to prevent
236			// races between marshaling and unmarshaling the lazily-{en,de}coded
237			// values.
238			mu.Lock()
239			defer mu.Unlock()
240		}
241	case map[int32]Extension:
242		m = exts
243	default:
244		return nil, errors.New("proto: not an extension map")
245	}
246	var b bytes.Buffer
247	b.WriteByte('{')
248
249	// Process the map in key order for deterministic output.
250	ids := make([]int32, 0, len(m))
251	for id := range m {
252		ids = append(ids, id)
253	}
254	sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
255
256	for i, id := range ids {
257		ext := m[id]
258		msd, ok := messageSetMap[id]
259		if !ok {
260			// Unknown type; we can't render it, so skip it.
261			continue
262		}
263
264		if i > 0 && b.Len() > 1 {
265			b.WriteByte(',')
266		}
267
268		fmt.Fprintf(&b, `"[%s]":`, msd.name)
269
270		x := ext.value
271		if x == nil {
272			x = reflect.New(msd.t.Elem()).Interface()
273			if err := Unmarshal(ext.enc, x.(Message)); err != nil {
274				return nil, err
275			}
276		}
277		d, err := json.Marshal(x)
278		if err != nil {
279			return nil, err
280		}
281		b.Write(d)
282	}
283	b.WriteByte('}')
284	return b.Bytes(), nil
285}
286
287// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
288// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
289func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
290	// Common-case fast path.
291	if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
292		return nil
293	}
294
295	// This is fairly tricky, and it's not clear that it is needed.
296	return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
297}
298
299// A global registry of types that can be used in a MessageSet.
300
301var messageSetMap = make(map[int32]messageSetDesc)
302
303type messageSetDesc struct {
304	t    reflect.Type // pointer to struct
305	name string
306}
307
308// RegisterMessageSetType is called from the generated code.
309func RegisterMessageSetType(m Message, fieldNum int32, name string) {
310	messageSetMap[fieldNum] = messageSetDesc{
311		t:    reflect.TypeOf(m),
312		name: name,
313	}
314}