github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/extensions.go (about) 1 // Go support for Protocol Buffers - Google's data interchange format 2 // 3 // Copyright 2010 The Go Authors. 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 32 package proto 33 34 /* 35 * Types and routines for supporting protocol buffer extensions. 36 */ 37 38 import ( 39 "errors" 40 "reflect" 41 "strconv" 42 "sync" 43 ) 44 45 // ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. 46 var ErrMissingExtension = errors.New("proto: missing extension") 47 48 // ExtensionRange represents a range of message extensions for a protocol buffer. 49 // Used in code generated by the protocol compiler. 50 type ExtensionRange struct { 51 Start, End int32 // both inclusive 52 } 53 54 // extendableProto is an interface implemented by any protocol buffer that may be extended. 55 type extendableProto interface { 56 Message 57 ExtensionRangeArray() []ExtensionRange 58 ExtensionMap() map[int32]Extension 59 } 60 61 var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() 62 63 // ExtensionDesc represents an extension specification. 64 // Used in generated code from the protocol compiler. 65 type ExtensionDesc struct { 66 ExtendedType Message // nil pointer to the type that is being extended 67 ExtensionType interface{} // nil pointer to the extension type 68 Field int32 // field number 69 Name string // fully-qualified name of extension, for text formatting 70 Tag string // protobuf tag style 71 } 72 73 func (ed *ExtensionDesc) repeated() bool { 74 t := reflect.TypeOf(ed.ExtensionType) 75 return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 76 } 77 78 // Extension represents an extension in a message. 79 type Extension struct { 80 // When an extension is stored in a message using SetExtension 81 // only desc and value are set. When the message is marshaled 82 // enc will be set to the encoded form of the message. 83 // 84 // When a message is unmarshaled and contains extensions, each 85 // extension will have only enc set. When such an extension is 86 // accessed using GetExtension (or GetExtensions) desc and value 87 // will be set. 88 desc *ExtensionDesc 89 value interface{} 90 enc []byte 91 } 92 93 // SetRawExtension is for testing only. 94 func SetRawExtension(base extendableProto, id int32, b []byte) { 95 base.ExtensionMap()[id] = Extension{enc: b} 96 } 97 98 // isExtensionField returns true iff the given field number is in an extension range. 99 func isExtensionField(pb extendableProto, field int32) bool { 100 for _, er := range pb.ExtensionRangeArray() { 101 if er.Start <= field && field <= er.End { 102 return true 103 } 104 } 105 return false 106 } 107 108 // checkExtensionTypes checks that the given extension is valid for pb. 109 func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { 110 // Check the extended type. 111 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { 112 return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) 113 } 114 // Check the range. 115 if !isExtensionField(pb, extension.Field) { 116 return errors.New("proto: bad extension number; not in declared ranges") 117 } 118 return nil 119 } 120 121 // extPropKey is sufficient to uniquely identify an extension. 122 type extPropKey struct { 123 base reflect.Type 124 field int32 125 } 126 127 var extProp = struct { 128 sync.RWMutex 129 m map[extPropKey]*Properties 130 }{ 131 m: make(map[extPropKey]*Properties), 132 } 133 134 func extensionProperties(ed *ExtensionDesc) *Properties { 135 key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} 136 137 extProp.RLock() 138 if prop, ok := extProp.m[key]; ok { 139 extProp.RUnlock() 140 return prop 141 } 142 extProp.RUnlock() 143 144 extProp.Lock() 145 defer extProp.Unlock() 146 // Check again. 147 if prop, ok := extProp.m[key]; ok { 148 return prop 149 } 150 151 prop := new(Properties) 152 prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) 153 extProp.m[key] = prop 154 return prop 155 } 156 157 // encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. 158 func encodeExtensionMap(m map[int32]Extension) error { 159 for k, e := range m { 160 if e.value == nil || e.desc == nil { 161 // Extension is only in its encoded form. 162 continue 163 } 164 165 // We don't skip extensions that have an encoded form set, 166 // because the extension value may have been mutated after 167 // the last time this function was called. 168 169 et := reflect.TypeOf(e.desc.ExtensionType) 170 props := extensionProperties(e.desc) 171 172 p := NewBuffer(nil) 173 // If e.value has type T, the encoder expects a *struct{ X T }. 174 // Pass a *T with a zero field and hope it all works out. 175 x := reflect.New(et) 176 x.Elem().Set(reflect.ValueOf(e.value)) 177 if err := props.enc(p, props, toStructPointer(x)); err != nil { 178 return err 179 } 180 e.enc = p.buf 181 m[k] = e 182 } 183 return nil 184 } 185 186 func sizeExtensionMap(m map[int32]Extension) (n int) { 187 for _, e := range m { 188 if e.value == nil || e.desc == nil { 189 // Extension is only in its encoded form. 190 n += len(e.enc) 191 continue 192 } 193 194 // We don't skip extensions that have an encoded form set, 195 // because the extension value may have been mutated after 196 // the last time this function was called. 197 198 et := reflect.TypeOf(e.desc.ExtensionType) 199 props := extensionProperties(e.desc) 200 201 // If e.value has type T, the encoder expects a *struct{ X T }. 202 // Pass a *T with a zero field and hope it all works out. 203 x := reflect.New(et) 204 x.Elem().Set(reflect.ValueOf(e.value)) 205 n += props.size(props, toStructPointer(x)) 206 } 207 return 208 } 209 210 // HasExtension returns whether the given extension is present in pb. 211 func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { 212 // TODO: Check types, field numbers, etc.? 213 _, ok := pb.ExtensionMap()[extension.Field] 214 return ok 215 } 216 217 // ClearExtension removes the given extension from pb. 218 func ClearExtension(pb extendableProto, extension *ExtensionDesc) { 219 // TODO: Check types, field numbers, etc.? 220 delete(pb.ExtensionMap(), extension.Field) 221 } 222 223 // GetExtension parses and returns the given extension of pb. 224 // If the extension is not present it returns ErrMissingExtension. 225 // If the returned extension is modified, SetExtension must be called 226 // for the modifications to be reflected in pb. 227 func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) { 228 if err := checkExtensionTypes(pb, extension); err != nil { 229 return nil, err 230 } 231 232 e, ok := pb.ExtensionMap()[extension.Field] 233 if !ok { 234 return nil, ErrMissingExtension 235 } 236 if e.value != nil { 237 // Already decoded. Check the descriptor, though. 238 if e.desc != extension { 239 // This shouldn't happen. If it does, it means that 240 // GetExtension was called twice with two different 241 // descriptors with the same field number. 242 return nil, errors.New("proto: descriptor conflict") 243 } 244 return e.value, nil 245 } 246 247 v, err := decodeExtension(e.enc, extension) 248 if err != nil { 249 return nil, err 250 } 251 252 // Remember the decoded version and drop the encoded version. 253 // That way it is safe to mutate what we return. 254 e.value = v 255 e.desc = extension 256 e.enc = nil 257 return e.value, nil 258 } 259 260 // decodeExtension decodes an extension encoded in b. 261 func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { 262 o := NewBuffer(b) 263 264 t := reflect.TypeOf(extension.ExtensionType) 265 rep := extension.repeated() 266 267 props := extensionProperties(extension) 268 269 // t is a pointer to a struct, pointer to basic type or a slice. 270 // Allocate a "field" to store the pointer/slice itself; the 271 // pointer/slice will be stored here. We pass 272 // the address of this field to props.dec. 273 // This passes a zero field and a *t and lets props.dec 274 // interpret it as a *struct{ x t }. 275 value := reflect.New(t).Elem() 276 277 for { 278 // Discard wire type and field number varint. It isn't needed. 279 if _, err := o.DecodeVarint(); err != nil { 280 return nil, err 281 } 282 283 if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { 284 return nil, err 285 } 286 287 if !rep || o.index >= len(o.buf) { 288 break 289 } 290 } 291 return value.Interface(), nil 292 } 293 294 // GetExtensions returns a slice of the extensions present in pb that are also listed in es. 295 // The returned slice has the same length as es; missing extensions will appear as nil elements. 296 func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { 297 epb, ok := pb.(extendableProto) 298 if !ok { 299 err = errors.New("proto: not an extendable proto") 300 return 301 } 302 extensions = make([]interface{}, len(es)) 303 for i, e := range es { 304 extensions[i], err = GetExtension(epb, e) 305 if err != nil { 306 return 307 } 308 } 309 return 310 } 311 312 // SetExtension sets the specified extension of pb to the specified value. 313 func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { 314 if err := checkExtensionTypes(pb, extension); err != nil { 315 return err 316 } 317 typ := reflect.TypeOf(extension.ExtensionType) 318 if typ != reflect.TypeOf(value) { 319 return errors.New("proto: bad extension value type") 320 } 321 322 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} 323 return nil 324 } 325 326 // A global registry of extensions. 327 // The generated code will register the generated descriptors by calling RegisterExtension. 328 329 var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) 330 331 // RegisterExtension is called from the generated code. 332 func RegisterExtension(desc *ExtensionDesc) { 333 st := reflect.TypeOf(desc.ExtendedType).Elem() 334 m := extensionMaps[st] 335 if m == nil { 336 m = make(map[int32]*ExtensionDesc) 337 extensionMaps[st] = m 338 } 339 if _, ok := m[desc.Field]; ok { 340 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) 341 } 342 m[desc.Field] = desc 343 } 344 345 // RegisteredExtensions returns a map of the registered extensions of a 346 // protocol buffer struct, indexed by the extension number. 347 // The argument pb should be a nil pointer to the struct type. 348 func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { 349 return extensionMaps[reflect.TypeOf(pb).Elem()] 350 }