blob: b9ba8b02498d7aaedcabcaf009507592bba09b86 [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 {
55 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100056 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070057}
58
59// ExtensionDesc represents an extension specification.
60// Used in generated code from the protocol compiler.
61type ExtensionDesc struct {
62 ExtendedType interface{} // nil pointer to the type that is being extended
63 ExtensionType interface{} // nil pointer to the extension type
64 Field int32 // field number
David Symondsc057ad52012-02-11 15:43:42 +110065 Name string // fully-qualified name of extension, for text formatting
David Symonds8935abf2011-07-04 15:53:16 +100066 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070067}
68
David Symonds61826da2012-05-05 09:31:28 +100069func (ed *ExtensionDesc) repeated() bool {
70 t := reflect.TypeOf(ed.ExtensionType)
71 return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
72}
73
David Symonds1d72f7a2011-08-19 18:28:52 +100074/*
75Extension represents an extension in a message.
76
77When an extension is stored in a message using SetExtension
78only desc and value are set. When the message is marshaled
79enc will be set to the encoded form of the message.
80
81When a message is unmarshaled and contains extensions, each
82extension will have only enc set. When such an extension is
83accessed using GetExtension (or GetExtensions) desc and value
84will be set.
85*/
86type Extension struct {
87 desc *ExtensionDesc
88 value interface{}
89 enc []byte
90}
91
92// SetRawExtension is for testing only.
93func SetRawExtension(base extendableProto, id int32, b []byte) {
94 base.ExtensionMap()[id] = Extension{enc: b}
95}
96
David Symonds940b9612011-04-01 10:45:23 +110097// isExtensionField returns true iff the given field number is in an extension range.
98func isExtensionField(pb extendableProto, field int32) bool {
99 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700100 if er.Start <= field && field <= er.End {
101 return true
102 }
103 }
104 return false
105}
106
David Symonds940b9612011-04-01 10:45:23 +1100107// checkExtensionTypes checks that the given extension is valid for pb.
Rob Pikea17fdd92011-11-02 12:43:05 -0700108func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700109 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000110 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikea17fdd92011-11-02 12:43:05 -0700111 return errors.New("bad extended type; " + b.String() + " does not extend " + a.String())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700112 }
113 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100114 if !isExtensionField(pb, extension.Field) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700115 return errors.New("bad extension number; not in declared ranges")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700116 }
117 return nil
118}
119
David Symonds1d72f7a2011-08-19 18:28:52 +1000120// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
Rob Pikea17fdd92011-11-02 12:43:05 -0700121func encodeExtensionMap(m map[int32]Extension) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000122 for k, e := range m {
123 if e.value == nil || e.desc == nil {
124 // Extension is only in its encoded form.
125 continue
126 }
127
128 // We don't skip extensions that have an encoded form set,
129 // because the extension value may have been mutated after
130 // the last time this function was called.
131
132 et := reflect.TypeOf(e.desc.ExtensionType)
133 props := new(Properties)
134 props.Init(et, "unknown_name", e.desc.Tag, 0)
135
136 p := NewBuffer(nil)
137 // The encoder must be passed a pointer to e.value.
138 // Allocate a copy of value so that we can use its address.
139 x := reflect.New(et)
140 x.Elem().Set(reflect.ValueOf(e.value))
141 if err := props.enc(p, props, x.Pointer()); err != nil {
142 return err
143 }
144 e.enc = p.buf
145 m[k] = e
146 }
147 return nil
148}
149
David Symonds940b9612011-04-01 10:45:23 +1100150// HasExtension returns whether the given extension is present in pb.
151func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100153 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700154 return ok
155}
156
David Symonds940b9612011-04-01 10:45:23 +1100157// ClearExtension removes the given extension from pb.
158func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700159 // TODO: Check types, field numbers, etc.?
Rob Pikef48475f2011-10-28 12:07:40 -0700160 delete(pb.ExtensionMap(), extension.Field)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161}
162
David Symonds940b9612011-04-01 10:45:23 +1100163// GetExtension parses and returns the given extension of pb.
David Symondsa7e9ef92012-01-18 18:27:58 +1100164// If the extension is not present it returns ErrMissingExtension.
Rob Pikea17fdd92011-11-02 12:43:05 -0700165func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
David Symonds940b9612011-04-01 10:45:23 +1100166 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167 return nil, err
168 }
169
David Symonds1d72f7a2011-08-19 18:28:52 +1000170 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700171 if !ok {
David Symondsa7e9ef92012-01-18 18:27:58 +1100172 return nil, ErrMissingExtension
Rob Pikeaaa3a622010-03-20 22:32:34 -0700173 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000174 if e.value != nil {
175 // Already decoded. Check the descriptor, though.
176 if e.desc != extension {
177 // This shouldn't happen. If it does, it means that
178 // GetExtension was called twice with two different
179 // descriptors with the same field number.
Rob Pikea17fdd92011-11-02 12:43:05 -0700180 return nil, errors.New("proto: descriptor conflict")
David Symonds1d72f7a2011-08-19 18:28:52 +1000181 }
182 return e.value, nil
183 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700184
David Symondsa4b61c02011-09-07 14:06:00 +1000185 v, err := decodeExtension(e.enc, extension)
186 if err != nil {
187 return nil, err
188 }
189
190 // Remember the decoded version and drop the encoded version.
191 // That way it is safe to mutate what we return.
192 e.value = v
193 e.desc = extension
194 e.enc = nil
195 return e.value, nil
196}
197
198// decodeExtension decodes an extension encoded in b.
Rob Pikea17fdd92011-11-02 12:43:05 -0700199func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
David Symonds61826da2012-05-05 09:31:28 +1000200 o := NewBuffer(b)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700201
Nigel Tao4ede8452011-04-28 11:27:25 +1000202 t := reflect.TypeOf(extension.ExtensionType)
David Symonds61826da2012-05-05 09:31:28 +1000203 rep := extension.repeated()
204
Rob Pikeaaa3a622010-03-20 22:32:34 -0700205 props := &Properties{}
206 props.Init(t, "irrelevant_name", extension.Tag, 0)
207
David Symonds61826da2012-05-05 09:31:28 +1000208 // t is a pointer to a struct, pointer to basic type or a slice.
209 // Allocate a "field" to store the pointer/slice itself; the
210 // pointer/slice will be stored here. We pass
Rob Pikeb0447c02011-10-20 15:20:04 -0700211 // the address of this field to props.dec.
212 value := reflect.New(t).Elem()
David Symonds61826da2012-05-05 09:31:28 +1000213
214 for {
215 // Discard wire type and field number varint. It isn't needed.
216 if _, err := o.DecodeVarint(); err != nil {
217 return nil, err
218 }
219
220 if err := props.dec(o, props, value.UnsafeAddr()); err != nil {
221 return nil, err
222 }
223
224 if !rep || o.index >= len(o.buf) {
225 break
226 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700227 }
Rob Pikeb0447c02011-10-20 15:20:04 -0700228 return value.Interface(), nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700229}
230
David Symonds940b9612011-04-01 10:45:23 +1100231// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
232// The returned slice has the same length as es; missing extensions will appear as nil elements.
Rob Pikea17fdd92011-11-02 12:43:05 -0700233func GetExtensions(pb interface{}, es []*ExtensionDesc) (extensions []interface{}, err error) {
David Symonds940b9612011-04-01 10:45:23 +1100234 epb, ok := pb.(extendableProto)
235 if !ok {
Rob Pikea17fdd92011-11-02 12:43:05 -0700236 err = errors.New("not an extendable proto")
David Symonds940b9612011-04-01 10:45:23 +1100237 return
238 }
239 extensions = make([]interface{}, len(es))
240 for i, e := range es {
241 extensions[i], err = GetExtension(epb, e)
242 if err != nil {
243 return
244 }
245 }
246 return
247}
248
David Symonds940b9612011-04-01 10:45:23 +1100249// SetExtension sets the specified extension of pb to the specified value.
Rob Pikea17fdd92011-11-02 12:43:05 -0700250func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
David Symonds940b9612011-04-01 10:45:23 +1100251 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700252 return err
253 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000254 typ := reflect.TypeOf(extension.ExtensionType)
255 if typ != reflect.TypeOf(value) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700256 return errors.New("bad extension value type")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700257 }
258
David Symonds1d72f7a2011-08-19 18:28:52 +1000259 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700260 return nil
261}
David Symondse37856c2011-06-22 12:52:53 +1000262
263// A global registry of extensions.
264// The generated code will register the generated descriptors by calling RegisterExtension.
265
266var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
267
268// RegisterExtension is called from the generated code.
269func RegisterExtension(desc *ExtensionDesc) {
270 st := reflect.TypeOf(desc.ExtendedType).Elem()
271 m := extensionMaps[st]
272 if m == nil {
273 m = make(map[int32]*ExtensionDesc)
274 extensionMaps[st] = m
275 }
276 if _, ok := m[desc.Field]; ok {
277 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
278 }
279 m[desc.Field] = desc
280}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000281
282// RegisteredExtensions returns a map of the registered extensions of a
283// protocol buffer struct, indexed by the extension number.
284// The argument pb should be a nil pointer to the struct type.
285func RegisteredExtensions(pb interface{}) map[int32]*ExtensionDesc {
286 return extensionMaps[reflect.TypeOf(pb).Elem()]
287}