blob: e929c8ba24fffd36e5b4b43aaadb6ab8675a545b [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
34
35/*
36 * Types and routines for supporting protocol buffer extensions.
37 */
38
39import (
40 "os"
41 "reflect"
David Symondse37856c2011-06-22 12:52:53 +100042 "strconv"
Rob Pikeaaa3a622010-03-20 22:32:34 -070043 "unsafe"
44)
45
46// ExtensionRange represents a range of message extensions for a protocol buffer.
47// Used in code generated by the protocol compiler.
48type ExtensionRange struct {
49 Start, End int32 // both inclusive
50}
51
52// extendableProto is an interface implemented by any protocol buffer that may be extended.
53type extendableProto interface {
54 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100055 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070056}
57
58// ExtensionDesc represents an extension specification.
59// Used in generated code from the protocol compiler.
60type ExtensionDesc struct {
61 ExtendedType interface{} // nil pointer to the type that is being extended
62 ExtensionType interface{} // nil pointer to the extension type
63 Field int32 // field number
David Symondse37856c2011-06-22 12:52:53 +100064 Name string // fully-qualified name of extension
David Symonds8935abf2011-07-04 15:53:16 +100065 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070066}
67
David Symonds1d72f7a2011-08-19 18:28:52 +100068/*
69Extension represents an extension in a message.
70
71When an extension is stored in a message using SetExtension
72only desc and value are set. When the message is marshaled
73enc will be set to the encoded form of the message.
74
75When a message is unmarshaled and contains extensions, each
76extension will have only enc set. When such an extension is
77accessed using GetExtension (or GetExtensions) desc and value
78will be set.
79*/
80type Extension struct {
81 desc *ExtensionDesc
82 value interface{}
83 enc []byte
84}
85
86// SetRawExtension is for testing only.
87func SetRawExtension(base extendableProto, id int32, b []byte) {
88 base.ExtensionMap()[id] = Extension{enc: b}
89}
90
David Symonds940b9612011-04-01 10:45:23 +110091// isExtensionField returns true iff the given field number is in an extension range.
92func isExtensionField(pb extendableProto, field int32) bool {
93 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -070094 if er.Start <= field && field <= er.End {
95 return true
96 }
97 }
98 return false
99}
100
David Symonds940b9612011-04-01 10:45:23 +1100101// checkExtensionTypes checks that the given extension is valid for pb.
102func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) os.Error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700103 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000104 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700105 return os.NewError("bad extended type; " + b.String() + " does not extend " + a.String())
106 }
107 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100108 if !isExtensionField(pb, extension.Field) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700109 return os.NewError("bad extension number; not in declared ranges")
110 }
111 return nil
112}
113
David Symonds1d72f7a2011-08-19 18:28:52 +1000114// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
115func encodeExtensionMap(m map[int32]Extension) os.Error {
116 for k, e := range m {
117 if e.value == nil || e.desc == nil {
118 // Extension is only in its encoded form.
119 continue
120 }
121
122 // We don't skip extensions that have an encoded form set,
123 // because the extension value may have been mutated after
124 // the last time this function was called.
125
126 et := reflect.TypeOf(e.desc.ExtensionType)
127 props := new(Properties)
128 props.Init(et, "unknown_name", e.desc.Tag, 0)
129
130 p := NewBuffer(nil)
131 // The encoder must be passed a pointer to e.value.
132 // Allocate a copy of value so that we can use its address.
133 x := reflect.New(et)
134 x.Elem().Set(reflect.ValueOf(e.value))
135 if err := props.enc(p, props, x.Pointer()); err != nil {
136 return err
137 }
138 e.enc = p.buf
139 m[k] = e
140 }
141 return nil
142}
143
David Symonds940b9612011-04-01 10:45:23 +1100144// HasExtension returns whether the given extension is present in pb.
145func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700146 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100147 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 return ok
149}
150
David Symonds940b9612011-04-01 10:45:23 +1100151// ClearExtension removes the given extension from pb.
152func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700153 // TODO: Check types, field numbers, etc.?
David Symonds1d72f7a2011-08-19 18:28:52 +1000154 pb.ExtensionMap()[extension.Field] = Extension{}, false
Rob Pikeaaa3a622010-03-20 22:32:34 -0700155}
156
David Symonds940b9612011-04-01 10:45:23 +1100157// GetExtension parses and returns the given extension of pb.
158// If the extension is not present it returns (nil, nil).
159func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, os.Error) {
160 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161 return nil, err
162 }
163
David Symonds1d72f7a2011-08-19 18:28:52 +1000164 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700165 if !ok {
166 return nil, nil // not an error
167 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000168 if e.value != nil {
169 // Already decoded. Check the descriptor, though.
170 if e.desc != extension {
171 // This shouldn't happen. If it does, it means that
172 // GetExtension was called twice with two different
173 // descriptors with the same field number.
174 return nil, os.NewError("proto: descriptor conflict")
175 }
176 return e.value, nil
177 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700178
179 // Discard wire type and field number varint. It isn't needed.
David Symonds1d72f7a2011-08-19 18:28:52 +1000180 _, n := DecodeVarint(e.enc)
181 o := NewBuffer(e.enc[n:])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700182
Nigel Tao4ede8452011-04-28 11:27:25 +1000183 t := reflect.TypeOf(extension.ExtensionType)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700184 props := &Properties{}
185 props.Init(t, "irrelevant_name", extension.Tag, 0)
186
187 base := unsafe.New(t)
188 var sbase uintptr
Rob Pike97e934d2011-04-11 12:52:49 -0700189 if t.Elem().Kind() == reflect.Struct {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700190 // props.dec will be dec_struct_message, which does not refer to sbase.
191 *(*unsafe.Pointer)(base) = unsafe.New(t.Elem())
192 } else {
193 sbase = uintptr(unsafe.New(t.Elem()))
194 }
195 if err := props.dec(o, props, uintptr(base), sbase); err != nil {
196 return nil, err
197 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000198 // Remember the decoded version and drop the encoded version.
199 // That way it is safe to mutate what we return.
200 e.value = unsafe.Unreflect(t, base)
201 e.desc = extension
202 e.enc = nil
203 return e.value, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700204}
205
David Symonds940b9612011-04-01 10:45:23 +1100206// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
207// The returned slice has the same length as es; missing extensions will appear as nil elements.
208func GetExtensions(pb interface{}, es []*ExtensionDesc) (extensions []interface{}, err os.Error) {
209 epb, ok := pb.(extendableProto)
210 if !ok {
211 err = os.NewError("not an extendable proto")
212 return
213 }
214 extensions = make([]interface{}, len(es))
215 for i, e := range es {
216 extensions[i], err = GetExtension(epb, e)
217 if err != nil {
218 return
219 }
220 }
221 return
222}
223
David Symondsc37ad662010-04-07 09:25:13 +1000224// TODO: (needed for repeated extensions)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700225// - ExtensionSize
226// - AddExtension
227
David Symonds940b9612011-04-01 10:45:23 +1100228// SetExtension sets the specified extension of pb to the specified value.
229func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) os.Error {
230 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 return err
232 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000233 typ := reflect.TypeOf(extension.ExtensionType)
234 if typ != reflect.TypeOf(value) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700235 return os.NewError("bad extension value type")
236 }
237
David Symonds1d72f7a2011-08-19 18:28:52 +1000238 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700239 return nil
240}
David Symondse37856c2011-06-22 12:52:53 +1000241
242// A global registry of extensions.
243// The generated code will register the generated descriptors by calling RegisterExtension.
244
245var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
246
247// RegisterExtension is called from the generated code.
248func RegisterExtension(desc *ExtensionDesc) {
249 st := reflect.TypeOf(desc.ExtendedType).Elem()
250 m := extensionMaps[st]
251 if m == nil {
252 m = make(map[int32]*ExtensionDesc)
253 extensionMaps[st] = m
254 }
255 if _, ok := m[desc.Field]; ok {
256 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
257 }
258 m[desc.Field] = desc
259}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000260
261// RegisteredExtensions returns a map of the registered extensions of a
262// protocol buffer struct, indexed by the extension number.
263// The argument pb should be a nil pointer to the struct type.
264func RegisteredExtensions(pb interface{}) map[int32]*ExtensionDesc {
265 return extensionMaps[reflect.TypeOf(pb).Elem()]
266}