blob: f1c52ccbeb6bd68591c9f3aec504618449e4ea1d [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 (
39 "os"
40 "reflect"
David Symondse37856c2011-06-22 12:52:53 +100041 "strconv"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042 "unsafe"
43)
44
45// ExtensionRange represents a range of message extensions for a protocol buffer.
46// Used in code generated by the protocol compiler.
47type ExtensionRange struct {
48 Start, End int32 // both inclusive
49}
50
51// extendableProto is an interface implemented by any protocol buffer that may be extended.
52type extendableProto interface {
53 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100054 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070055}
56
57// ExtensionDesc represents an extension specification.
58// Used in generated code from the protocol compiler.
59type ExtensionDesc struct {
60 ExtendedType interface{} // nil pointer to the type that is being extended
61 ExtensionType interface{} // nil pointer to the extension type
62 Field int32 // field number
David Symondse37856c2011-06-22 12:52:53 +100063 Name string // fully-qualified name of extension
David Symonds8935abf2011-07-04 15:53:16 +100064 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070065}
66
David Symonds1d72f7a2011-08-19 18:28:52 +100067/*
68Extension represents an extension in a message.
69
70When an extension is stored in a message using SetExtension
71only desc and value are set. When the message is marshaled
72enc will be set to the encoded form of the message.
73
74When a message is unmarshaled and contains extensions, each
75extension will have only enc set. When such an extension is
76accessed using GetExtension (or GetExtensions) desc and value
77will be set.
78*/
79type Extension struct {
80 desc *ExtensionDesc
81 value interface{}
82 enc []byte
83}
84
85// SetRawExtension is for testing only.
86func SetRawExtension(base extendableProto, id int32, b []byte) {
87 base.ExtensionMap()[id] = Extension{enc: b}
88}
89
David Symonds940b9612011-04-01 10:45:23 +110090// isExtensionField returns true iff the given field number is in an extension range.
91func isExtensionField(pb extendableProto, field int32) bool {
92 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -070093 if er.Start <= field && field <= er.End {
94 return true
95 }
96 }
97 return false
98}
99
David Symonds940b9612011-04-01 10:45:23 +1100100// checkExtensionTypes checks that the given extension is valid for pb.
101func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) os.Error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700102 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000103 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700104 return os.NewError("bad extended type; " + b.String() + " does not extend " + a.String())
105 }
106 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100107 if !isExtensionField(pb, extension.Field) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700108 return os.NewError("bad extension number; not in declared ranges")
109 }
110 return nil
111}
112
David Symonds1d72f7a2011-08-19 18:28:52 +1000113// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
114func encodeExtensionMap(m map[int32]Extension) os.Error {
115 for k, e := range m {
116 if e.value == nil || e.desc == nil {
117 // Extension is only in its encoded form.
118 continue
119 }
120
121 // We don't skip extensions that have an encoded form set,
122 // because the extension value may have been mutated after
123 // the last time this function was called.
124
125 et := reflect.TypeOf(e.desc.ExtensionType)
126 props := new(Properties)
127 props.Init(et, "unknown_name", e.desc.Tag, 0)
128
129 p := NewBuffer(nil)
130 // The encoder must be passed a pointer to e.value.
131 // Allocate a copy of value so that we can use its address.
132 x := reflect.New(et)
133 x.Elem().Set(reflect.ValueOf(e.value))
134 if err := props.enc(p, props, x.Pointer()); err != nil {
135 return err
136 }
137 e.enc = p.buf
138 m[k] = e
139 }
140 return nil
141}
142
David Symonds940b9612011-04-01 10:45:23 +1100143// HasExtension returns whether the given extension is present in pb.
144func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700145 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100146 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700147 return ok
148}
149
David Symonds940b9612011-04-01 10:45:23 +1100150// ClearExtension removes the given extension from pb.
151func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 // TODO: Check types, field numbers, etc.?
David Symonds1d72f7a2011-08-19 18:28:52 +1000153 pb.ExtensionMap()[extension.Field] = Extension{}, false
Rob Pikeaaa3a622010-03-20 22:32:34 -0700154}
155
David Symonds940b9612011-04-01 10:45:23 +1100156// GetExtension parses and returns the given extension of pb.
157// If the extension is not present it returns (nil, nil).
158func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, os.Error) {
159 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160 return nil, err
161 }
162
David Symonds1d72f7a2011-08-19 18:28:52 +1000163 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700164 if !ok {
165 return nil, nil // not an error
166 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000167 if e.value != nil {
168 // Already decoded. Check the descriptor, though.
169 if e.desc != extension {
170 // This shouldn't happen. If it does, it means that
171 // GetExtension was called twice with two different
172 // descriptors with the same field number.
173 return nil, os.NewError("proto: descriptor conflict")
174 }
175 return e.value, nil
176 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700177
David Symondsa4b61c02011-09-07 14:06:00 +1000178 v, err := decodeExtension(e.enc, extension)
179 if err != nil {
180 return nil, err
181 }
182
183 // Remember the decoded version and drop the encoded version.
184 // That way it is safe to mutate what we return.
185 e.value = v
186 e.desc = extension
187 e.enc = nil
188 return e.value, nil
189}
190
191// decodeExtension decodes an extension encoded in b.
192func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, os.Error) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700193 // Discard wire type and field number varint. It isn't needed.
David Symondsa4b61c02011-09-07 14:06:00 +1000194 _, n := DecodeVarint(b)
195 o := NewBuffer(b[n:])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700196
Nigel Tao4ede8452011-04-28 11:27:25 +1000197 t := reflect.TypeOf(extension.ExtensionType)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700198 props := &Properties{}
199 props.Init(t, "irrelevant_name", extension.Tag, 0)
200
201 base := unsafe.New(t)
Rob Pike97e934d2011-04-11 12:52:49 -0700202 if t.Elem().Kind() == reflect.Struct {
Rob Pike76f6ee52011-10-20 12:58:28 -0700203 // props.dec will be dec_struct_message.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700204 *(*unsafe.Pointer)(base) = unsafe.New(t.Elem())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700205 }
Rob Pike76f6ee52011-10-20 12:58:28 -0700206 if err := props.dec(o, props, uintptr(base)); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700207 return nil, err
208 }
David Symondsa4b61c02011-09-07 14:06:00 +1000209 return unsafe.Unreflect(t, base), nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700210}
211
David Symonds940b9612011-04-01 10:45:23 +1100212// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
213// The returned slice has the same length as es; missing extensions will appear as nil elements.
214func GetExtensions(pb interface{}, es []*ExtensionDesc) (extensions []interface{}, err os.Error) {
215 epb, ok := pb.(extendableProto)
216 if !ok {
217 err = os.NewError("not an extendable proto")
218 return
219 }
220 extensions = make([]interface{}, len(es))
221 for i, e := range es {
222 extensions[i], err = GetExtension(epb, e)
223 if err != nil {
224 return
225 }
226 }
227 return
228}
229
David Symondsc37ad662010-04-07 09:25:13 +1000230// TODO: (needed for repeated extensions)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231// - ExtensionSize
232// - AddExtension
233
David Symonds940b9612011-04-01 10:45:23 +1100234// SetExtension sets the specified extension of pb to the specified value.
235func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) os.Error {
236 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700237 return err
238 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000239 typ := reflect.TypeOf(extension.ExtensionType)
240 if typ != reflect.TypeOf(value) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 return os.NewError("bad extension value type")
242 }
243
David Symonds1d72f7a2011-08-19 18:28:52 +1000244 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700245 return nil
246}
David Symondse37856c2011-06-22 12:52:53 +1000247
248// A global registry of extensions.
249// The generated code will register the generated descriptors by calling RegisterExtension.
250
251var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
252
253// RegisterExtension is called from the generated code.
254func RegisterExtension(desc *ExtensionDesc) {
255 st := reflect.TypeOf(desc.ExtendedType).Elem()
256 m := extensionMaps[st]
257 if m == nil {
258 m = make(map[int32]*ExtensionDesc)
259 extensionMaps[st] = m
260 }
261 if _, ok := m[desc.Field]; ok {
262 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
263 }
264 m[desc.Field] = desc
265}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000266
267// RegisteredExtensions returns a map of the registered extensions of a
268// protocol buffer struct, indexed by the extension number.
269// The argument pb should be a nil pointer to the struct type.
270func RegisteredExtensions(pb interface{}) map[int32]*ExtensionDesc {
271 return extensionMaps[reflect.TypeOf(pb).Elem()]
272}