blob: d3d5d5c52d93540db4bcd5ed03b5d8e15a9ffce6 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// 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
32package proto
33
Rob Pikeaaa3a622010-03-20 22:32:34 -070034/*
35 * Types and routines for supporting protocol buffer extensions.
36 */
37
38import (
Rob Pikea17fdd92011-11-02 12:43:05 -070039 "errors"
Rob Pikeaaa3a622010-03-20 22:32:34 -070040 "reflect"
David Symondse37856c2011-06-22 12:52:53 +100041 "strconv"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042)
43
David Symondsa7e9ef92012-01-18 18:27:58 +110044// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
45var ErrMissingExtension = errors.New("proto: missing extension")
46
Rob Pikeaaa3a622010-03-20 22:32:34 -070047// ExtensionRange represents a range of message extensions for a protocol buffer.
48// Used in code generated by the protocol compiler.
49type ExtensionRange struct {
50 Start, End int32 // both inclusive
51}
52
53// extendableProto is an interface implemented by any protocol buffer that may be extended.
54type extendableProto interface {
David Symonds9f60f432012-06-14 09:45:25 +100055 Message
Rob Pikeaaa3a622010-03-20 22:32:34 -070056 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100057 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070058}
59
60// ExtensionDesc represents an extension specification.
61// Used in generated code from the protocol compiler.
62type ExtensionDesc struct {
David Symonds9f60f432012-06-14 09:45:25 +100063 ExtendedType Message // nil pointer to the type that is being extended
Rob Pikeaaa3a622010-03-20 22:32:34 -070064 ExtensionType interface{} // nil pointer to the extension type
65 Field int32 // field number
David Symondsc057ad52012-02-11 15:43:42 +110066 Name string // fully-qualified name of extension, for text formatting
David Symonds8935abf2011-07-04 15:53:16 +100067 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070068}
69
David Symonds61826da2012-05-05 09:31:28 +100070func (ed *ExtensionDesc) repeated() bool {
71 t := reflect.TypeOf(ed.ExtensionType)
72 return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
73}
74
David Symonds1d72f7a2011-08-19 18:28:52 +100075/*
76Extension represents an extension in a message.
77
78When an extension is stored in a message using SetExtension
79only desc and value are set. When the message is marshaled
80enc will be set to the encoded form of the message.
81
82When a message is unmarshaled and contains extensions, each
83extension will have only enc set. When such an extension is
84accessed using GetExtension (or GetExtensions) desc and value
85will be set.
86*/
87type Extension struct {
88 desc *ExtensionDesc
89 value interface{}
90 enc []byte
91}
92
93// SetRawExtension is for testing only.
94func SetRawExtension(base extendableProto, id int32, b []byte) {
95 base.ExtensionMap()[id] = Extension{enc: b}
96}
97
David Symonds940b9612011-04-01 10:45:23 +110098// isExtensionField returns true iff the given field number is in an extension range.
99func isExtensionField(pb extendableProto, field int32) bool {
100 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700101 if er.Start <= field && field <= er.End {
102 return true
103 }
104 }
105 return false
106}
107
David Symonds940b9612011-04-01 10:45:23 +1100108// checkExtensionTypes checks that the given extension is valid for pb.
Rob Pikea17fdd92011-11-02 12:43:05 -0700109func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700110 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000111 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikea17fdd92011-11-02 12:43:05 -0700112 return errors.New("bad extended type; " + b.String() + " does not extend " + a.String())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700113 }
114 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100115 if !isExtensionField(pb, extension.Field) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700116 return errors.New("bad extension number; not in declared ranges")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700117 }
118 return nil
119}
120
David Symonds1d72f7a2011-08-19 18:28:52 +1000121// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
Rob Pikea17fdd92011-11-02 12:43:05 -0700122func encodeExtensionMap(m map[int32]Extension) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000123 for k, e := range m {
124 if e.value == nil || e.desc == nil {
125 // Extension is only in its encoded form.
126 continue
127 }
128
129 // We don't skip extensions that have an encoded form set,
130 // because the extension value may have been mutated after
131 // the last time this function was called.
132
133 et := reflect.TypeOf(e.desc.ExtensionType)
134 props := new(Properties)
135 props.Init(et, "unknown_name", e.desc.Tag, 0)
136
137 p := NewBuffer(nil)
138 // The encoder must be passed a pointer to e.value.
139 // Allocate a copy of value so that we can use its address.
140 x := reflect.New(et)
141 x.Elem().Set(reflect.ValueOf(e.value))
142 if err := props.enc(p, props, x.Pointer()); err != nil {
143 return err
144 }
145 e.enc = p.buf
146 m[k] = e
147 }
148 return nil
149}
150
David Symonds940b9612011-04-01 10:45:23 +1100151// HasExtension returns whether the given extension is present in pb.
152func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700153 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100154 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700155 return ok
156}
157
David Symonds940b9612011-04-01 10:45:23 +1100158// ClearExtension removes the given extension from pb.
159func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160 // TODO: Check types, field numbers, etc.?
Rob Pikef48475f2011-10-28 12:07:40 -0700161 delete(pb.ExtensionMap(), extension.Field)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700162}
163
David Symonds940b9612011-04-01 10:45:23 +1100164// GetExtension parses and returns the given extension of pb.
David Symondsa7e9ef92012-01-18 18:27:58 +1100165// If the extension is not present it returns ErrMissingExtension.
Rob Pikea17fdd92011-11-02 12:43:05 -0700166func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
David Symonds940b9612011-04-01 10:45:23 +1100167 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700168 return nil, err
169 }
170
David Symonds1d72f7a2011-08-19 18:28:52 +1000171 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700172 if !ok {
David Symondsa7e9ef92012-01-18 18:27:58 +1100173 return nil, ErrMissingExtension
Rob Pikeaaa3a622010-03-20 22:32:34 -0700174 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000175 if e.value != nil {
176 // Already decoded. Check the descriptor, though.
177 if e.desc != extension {
178 // This shouldn't happen. If it does, it means that
179 // GetExtension was called twice with two different
180 // descriptors with the same field number.
Rob Pikea17fdd92011-11-02 12:43:05 -0700181 return nil, errors.New("proto: descriptor conflict")
David Symonds1d72f7a2011-08-19 18:28:52 +1000182 }
183 return e.value, nil
184 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700185
David Symondsa4b61c02011-09-07 14:06:00 +1000186 v, err := decodeExtension(e.enc, extension)
187 if err != nil {
188 return nil, err
189 }
190
191 // Remember the decoded version and drop the encoded version.
192 // That way it is safe to mutate what we return.
193 e.value = v
194 e.desc = extension
195 e.enc = nil
196 return e.value, nil
197}
198
199// decodeExtension decodes an extension encoded in b.
Rob Pikea17fdd92011-11-02 12:43:05 -0700200func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
David Symonds61826da2012-05-05 09:31:28 +1000201 o := NewBuffer(b)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700202
Nigel Tao4ede8452011-04-28 11:27:25 +1000203 t := reflect.TypeOf(extension.ExtensionType)
David Symonds61826da2012-05-05 09:31:28 +1000204 rep := extension.repeated()
205
Rob Pikeaaa3a622010-03-20 22:32:34 -0700206 props := &Properties{}
207 props.Init(t, "irrelevant_name", extension.Tag, 0)
208
David Symonds61826da2012-05-05 09:31:28 +1000209 // t is a pointer to a struct, pointer to basic type or a slice.
210 // Allocate a "field" to store the pointer/slice itself; the
211 // pointer/slice will be stored here. We pass
Rob Pikeb0447c02011-10-20 15:20:04 -0700212 // the address of this field to props.dec.
213 value := reflect.New(t).Elem()
David Symonds61826da2012-05-05 09:31:28 +1000214
215 for {
216 // Discard wire type and field number varint. It isn't needed.
217 if _, err := o.DecodeVarint(); err != nil {
218 return nil, err
219 }
220
221 if err := props.dec(o, props, value.UnsafeAddr()); err != nil {
222 return nil, err
223 }
224
225 if !rep || o.index >= len(o.buf) {
226 break
227 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700228 }
Rob Pikeb0447c02011-10-20 15:20:04 -0700229 return value.Interface(), nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700230}
231
David Symonds940b9612011-04-01 10:45:23 +1100232// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
233// The returned slice has the same length as es; missing extensions will appear as nil elements.
David Symonds9f60f432012-06-14 09:45:25 +1000234func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
David Symonds940b9612011-04-01 10:45:23 +1100235 epb, ok := pb.(extendableProto)
236 if !ok {
Rob Pikea17fdd92011-11-02 12:43:05 -0700237 err = errors.New("not an extendable proto")
David Symonds940b9612011-04-01 10:45:23 +1100238 return
239 }
240 extensions = make([]interface{}, len(es))
241 for i, e := range es {
242 extensions[i], err = GetExtension(epb, e)
243 if err != nil {
244 return
245 }
246 }
247 return
248}
249
David Symonds940b9612011-04-01 10:45:23 +1100250// SetExtension sets the specified extension of pb to the specified value.
Rob Pikea17fdd92011-11-02 12:43:05 -0700251func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
David Symonds940b9612011-04-01 10:45:23 +1100252 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700253 return err
254 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000255 typ := reflect.TypeOf(extension.ExtensionType)
256 if typ != reflect.TypeOf(value) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700257 return errors.New("bad extension value type")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700258 }
259
David Symonds1d72f7a2011-08-19 18:28:52 +1000260 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700261 return nil
262}
David Symondse37856c2011-06-22 12:52:53 +1000263
264// A global registry of extensions.
265// The generated code will register the generated descriptors by calling RegisterExtension.
266
267var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
268
269// RegisterExtension is called from the generated code.
270func RegisterExtension(desc *ExtensionDesc) {
271 st := reflect.TypeOf(desc.ExtendedType).Elem()
272 m := extensionMaps[st]
273 if m == nil {
274 m = make(map[int32]*ExtensionDesc)
275 extensionMaps[st] = m
276 }
277 if _, ok := m[desc.Field]; ok {
278 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
279 }
280 m[desc.Field] = desc
281}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000282
283// RegisteredExtensions returns a map of the registered extensions of a
284// protocol buffer struct, indexed by the extension number.
285// The argument pb should be a nil pointer to the struct type.
David Symonds9f60f432012-06-14 09:45:25 +1000286func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
David Symondsc7cb3fd2011-08-29 16:49:58 +1000287 return extensionMaps[reflect.TypeOf(pb).Elem()]
288}