initialise
[debian/goprotobuf.git] / proto / message_set.go
1 // Go support for Protocol Buffers - Google's data interchange format
2 //
3 // Copyright 2010 Google Inc.  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         "bytes"
40         "os"
41         "reflect"
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 = os.NewError("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 *bytes.Buffer
74         // TODO: caching?
75 }
76
77 // messageTypeIder is an interface satisfied by a protocol buffer type
78 // that may be stored in a MessageSet.
79 type messageTypeIder interface {
80         MessageTypeId() int32
81 }
82
83 func (ms *MessageSet) find(pb interface{}) *_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
97 func (ms *MessageSet) Has(pb interface{}) bool {
98         if ms.find(pb) != nil {
99                 return true
100         }
101         return false
102 }
103
104 func (ms *MessageSet) Unmarshal(pb interface{}) os.Error {
105         if item := ms.find(pb); item != nil {
106                 return Unmarshal(item.Message, pb)
107         }
108         if _, ok := pb.(messageTypeIder); !ok {
109                 return ErrNoMessageTypeId
110         }
111         return nil // TODO: return error instead?
112 }
113
114 func (ms *MessageSet) Marshal(pb interface{}) os.Error {
115         msg, err := Marshal(pb)
116         if err != nil {
117                 return err
118         }
119         if item := ms.find(pb); item != nil {
120                 // reuse existing item
121                 item.Message = msg
122                 return nil
123         }
124
125         mti, ok := pb.(messageTypeIder)
126         if !ok {
127                 return ErrWrongType // TODO: custom error?
128         }
129
130         mtid := mti.MessageTypeId()
131         ms.Item = append(ms.Item, &_MessageSet_Item{
132                 TypeId:  &mtid,
133                 Message: msg,
134         })
135         return nil
136 }
137
138 // Support for the message_set_wire_format message option.
139
140 func skipVarint(buf []byte) []byte {
141         i := 0
142         for ; buf[i]&0x80 != 0; i++ {
143         }
144         return buf[i+1:]
145 }
146
147 // MarshalMessageSet encodes the extension map represented by m in the message set wire format.
148 // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
149 func MarshalMessageSet(m map[int32]Extension) ([]byte, os.Error) {
150         if err := encodeExtensionMap(m); err != nil {
151                 return nil, err
152         }
153
154         ms := &MessageSet{Item: make([]*_MessageSet_Item, len(m))}
155         i := 0
156         for k, e := range m {
157                 // Remove the wire type and field number varint, as well as the length varint.
158                 msg := skipVarint(skipVarint(e.enc))
159
160                 ms.Item[i] = &_MessageSet_Item{
161                         TypeId:  Int32(k),
162                         Message: msg,
163                 }
164                 i++
165         }
166         return Marshal(ms)
167 }
168
169 // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
170 // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
171 func UnmarshalMessageSet(buf []byte, m map[int32]Extension) os.Error {
172         ms := new(MessageSet)
173         if err := Unmarshal(buf, ms); err != nil {
174                 return err
175         }
176         for _, item := range ms.Item {
177                 // restore wire type and field number varint, plus length varint.
178                 b := EncodeVarint(uint64(*item.TypeId)<<3 | WireBytes)
179                 b = append(b, EncodeVarint(uint64(len(item.Message)))...)
180                 b = append(b, item.Message...)
181
182                 m[*item.TypeId] = Extension{enc: b}
183         }
184         return nil
185 }
186
187 // A global registry of types that can be used in a MessageSet.
188
189 var messageSetMap = make(map[int32]messageSetDesc)
190
191 type messageSetDesc struct {
192         t    reflect.Type // pointer to struct
193         name string
194 }
195
196 // RegisterMessageSetType is called from the generated code.
197 func RegisterMessageSetType(i messageTypeIder, name string) {
198         messageSetMap[i.MessageTypeId()] = messageSetDesc{
199                 t:    reflect.TypeOf(i),
200                 name: name,
201         }
202 }