blob: e6b7b551c7fdcb2aa5943694984c365e610a437d [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)
43
44// ExtensionRange represents a range of message extensions for a protocol buffer.
45// Used in code generated by the protocol compiler.
46type ExtensionRange struct {
47 Start, End int32 // both inclusive
48}
49
50// extendableProto is an interface implemented by any protocol buffer that may be extended.
51type extendableProto interface {
52 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100053 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070054}
55
56// ExtensionDesc represents an extension specification.
57// Used in generated code from the protocol compiler.
58type ExtensionDesc struct {
59 ExtendedType interface{} // nil pointer to the type that is being extended
60 ExtensionType interface{} // nil pointer to the extension type
61 Field int32 // field number
David Symondse37856c2011-06-22 12:52:53 +100062 Name string // fully-qualified name of extension
David Symonds8935abf2011-07-04 15:53:16 +100063 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070064}
65
David Symonds1d72f7a2011-08-19 18:28:52 +100066/*
67Extension represents an extension in a message.
68
69When an extension is stored in a message using SetExtension
70only desc and value are set. When the message is marshaled
71enc will be set to the encoded form of the message.
72
73When a message is unmarshaled and contains extensions, each
74extension will have only enc set. When such an extension is
75accessed using GetExtension (or GetExtensions) desc and value
76will be set.
77*/
78type Extension struct {
79 desc *ExtensionDesc
80 value interface{}
81 enc []byte
82}
83
84// SetRawExtension is for testing only.
85func SetRawExtension(base extendableProto, id int32, b []byte) {
86 base.ExtensionMap()[id] = Extension{enc: b}
87}
88
David Symonds940b9612011-04-01 10:45:23 +110089// isExtensionField returns true iff the given field number is in an extension range.
90func isExtensionField(pb extendableProto, field int32) bool {
91 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -070092 if er.Start <= field && field <= er.End {
93 return true
94 }
95 }
96 return false
97}
98
David Symonds940b9612011-04-01 10:45:23 +110099// checkExtensionTypes checks that the given extension is valid for pb.
100func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) os.Error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700101 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000102 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700103 return os.NewError("bad extended type; " + b.String() + " does not extend " + a.String())
104 }
105 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100106 if !isExtensionField(pb, extension.Field) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700107 return os.NewError("bad extension number; not in declared ranges")
108 }
109 return nil
110}
111
David Symonds1d72f7a2011-08-19 18:28:52 +1000112// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
113func encodeExtensionMap(m map[int32]Extension) os.Error {
114 for k, e := range m {
115 if e.value == nil || e.desc == nil {
116 // Extension is only in its encoded form.
117 continue
118 }
119
120 // We don't skip extensions that have an encoded form set,
121 // because the extension value may have been mutated after
122 // the last time this function was called.
123
124 et := reflect.TypeOf(e.desc.ExtensionType)
125 props := new(Properties)
126 props.Init(et, "unknown_name", e.desc.Tag, 0)
127
128 p := NewBuffer(nil)
129 // The encoder must be passed a pointer to e.value.
130 // Allocate a copy of value so that we can use its address.
131 x := reflect.New(et)
132 x.Elem().Set(reflect.ValueOf(e.value))
133 if err := props.enc(p, props, x.Pointer()); err != nil {
134 return err
135 }
136 e.enc = p.buf
137 m[k] = e
138 }
139 return nil
140}
141
David Symonds940b9612011-04-01 10:45:23 +1100142// HasExtension returns whether the given extension is present in pb.
143func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700144 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100145 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700146 return ok
147}
148
David Symonds940b9612011-04-01 10:45:23 +1100149// ClearExtension removes the given extension from pb.
150func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700151 // TODO: Check types, field numbers, etc.?
Rob Pikef48475f2011-10-28 12:07:40 -0700152 delete(pb.ExtensionMap(), extension.Field)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700153}
154
David Symonds940b9612011-04-01 10:45:23 +1100155// GetExtension parses and returns the given extension of pb.
156// If the extension is not present it returns (nil, nil).
157func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, os.Error) {
158 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700159 return nil, err
160 }
161
David Symonds1d72f7a2011-08-19 18:28:52 +1000162 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700163 if !ok {
164 return nil, nil // not an error
165 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000166 if e.value != nil {
167 // Already decoded. Check the descriptor, though.
168 if e.desc != extension {
169 // This shouldn't happen. If it does, it means that
170 // GetExtension was called twice with two different
171 // descriptors with the same field number.
172 return nil, os.NewError("proto: descriptor conflict")
173 }
174 return e.value, nil
175 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700176
David Symondsa4b61c02011-09-07 14:06:00 +1000177 v, err := decodeExtension(e.enc, extension)
178 if err != nil {
179 return nil, err
180 }
181
182 // Remember the decoded version and drop the encoded version.
183 // That way it is safe to mutate what we return.
184 e.value = v
185 e.desc = extension
186 e.enc = nil
187 return e.value, nil
188}
189
190// decodeExtension decodes an extension encoded in b.
191func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, os.Error) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700192 // Discard wire type and field number varint. It isn't needed.
David Symondsa4b61c02011-09-07 14:06:00 +1000193 _, n := DecodeVarint(b)
194 o := NewBuffer(b[n:])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700195
Nigel Tao4ede8452011-04-28 11:27:25 +1000196 t := reflect.TypeOf(extension.ExtensionType)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700197 props := &Properties{}
198 props.Init(t, "irrelevant_name", extension.Tag, 0)
199
Rob Pikeb0447c02011-10-20 15:20:04 -0700200 // t is a pointer, likely to a struct.
201 // Allocate a "field" to store the pointer itself; the
202 // struct pointer will be stored here. We pass
203 // the address of this field to props.dec.
204 value := reflect.New(t).Elem()
205 if err := props.dec(o, props, value.UnsafeAddr()); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700206 return nil, err
207 }
Rob Pikeb0447c02011-10-20 15:20:04 -0700208 return value.Interface(), nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209}
210
David Symonds940b9612011-04-01 10:45:23 +1100211// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
212// The returned slice has the same length as es; missing extensions will appear as nil elements.
213func GetExtensions(pb interface{}, es []*ExtensionDesc) (extensions []interface{}, err os.Error) {
214 epb, ok := pb.(extendableProto)
215 if !ok {
216 err = os.NewError("not an extendable proto")
217 return
218 }
219 extensions = make([]interface{}, len(es))
220 for i, e := range es {
221 extensions[i], err = GetExtension(epb, e)
222 if err != nil {
223 return
224 }
225 }
226 return
227}
228
David Symondsc37ad662010-04-07 09:25:13 +1000229// TODO: (needed for repeated extensions)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700230// - ExtensionSize
231// - AddExtension
232
David Symonds940b9612011-04-01 10:45:23 +1100233// SetExtension sets the specified extension of pb to the specified value.
234func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) os.Error {
235 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700236 return err
237 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000238 typ := reflect.TypeOf(extension.ExtensionType)
239 if typ != reflect.TypeOf(value) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700240 return os.NewError("bad extension value type")
241 }
242
David Symonds1d72f7a2011-08-19 18:28:52 +1000243 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700244 return nil
245}
David Symondse37856c2011-06-22 12:52:53 +1000246
247// A global registry of extensions.
248// The generated code will register the generated descriptors by calling RegisterExtension.
249
250var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
251
252// RegisterExtension is called from the generated code.
253func RegisterExtension(desc *ExtensionDesc) {
254 st := reflect.TypeOf(desc.ExtendedType).Elem()
255 m := extensionMaps[st]
256 if m == nil {
257 m = make(map[int32]*ExtensionDesc)
258 extensionMaps[st] = m
259 }
260 if _, ok := m[desc.Field]; ok {
261 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
262 }
263 m[desc.Field] = desc
264}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000265
266// RegisteredExtensions returns a map of the registered extensions of a
267// protocol buffer struct, indexed by the extension number.
268// The argument pb should be a nil pointer to the struct type.
269func RegisteredExtensions(pb interface{}) map[int32]*ExtensionDesc {
270 return extensionMaps[reflect.TypeOf(pb).Elem()]
271}