blob: 722614ffc56f22c2ef08a9eae061a973034d70b4 [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 * Routines for encoding data into the wire format for protocol buffers.
36 */
37
38import (
39 "fmt"
40 "os"
41 "reflect"
42 "runtime"
43 "strconv"
44 "strings"
45 "sync"
46 "unsafe"
47)
48
49const debug bool = false
50
51// Constants that identify the encoding of a value on the wire.
52const (
53 WireVarint = 0
54 WireFixed64 = 1
55 WireBytes = 2
56 WireStartGroup = 3
57 WireEndGroup = 4
58 WireFixed32 = 5
59)
60
61const startSize = 10 // initial slice/string sizes
62
63// Encoders are defined in encoder.go
64// An encoder outputs the full representation of a field, including its
65// tag and encoder type.
66type encoder func(p *Buffer, prop *Properties, base uintptr) os.Error
67
68// A valueEncoder encodes a single integer in a particular encoding.
69type valueEncoder func(o *Buffer, x uint64) os.Error
70
71// Decoders are defined in decode.go
72// A decoder creates a value from its wire representation.
73// Unrecognized subelements are saved in unrec.
74type decoder func(p *Buffer, prop *Properties, base uintptr, sbase uintptr) os.Error
75
76// A valueDecoder decodes a single integer in a particular encoding.
77type valueDecoder func(o *Buffer) (x uint64, err os.Error)
78
79// StructProperties represents properties for all the fields of a struct.
80type StructProperties struct {
81 Prop []*Properties // properties for each field
82 reqCount int // required count
83 tags map[int]int // map from proto tag to struct field number
84 nscratch uintptr // size of scratch space
85}
86
87// Properties represents the protocol-specific behavior of a single struct field.
88type Properties struct {
89 Name string // name of the field, for error messages
90 OrigName string // original name before protocol compiler (always set)
91 Wire string
92 WireType int
93 Tag int
94 Required bool
95 Optional bool
96 Repeated bool
97 Enum string // set for enum types only
98 Default string // default value
99 def_uint64 uint64
100
101 enc encoder
102 valEnc valueEncoder // set for bool and numeric types only
103 offset uintptr
104 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
105 tagbuf [8]byte
106 stype *reflect.PtrType
107
108 dec decoder
109 valDec valueDecoder // set for bool and numeric types only
110 scratch uintptr
111 sizeof int // calculations of scratch space
112 alignof int
113}
114
115// String formats the properties in the "PB(...)" struct tag style.
116func (p *Properties) String() string {
117 s := p.Wire
118 s = ","
119 s += strconv.Itoa(p.Tag)
120 if p.Required {
121 s += ",req"
122 }
123 if p.Optional {
124 s += ",opt"
125 }
126 if p.Repeated {
127 s += ",rep"
128 }
129 if p.OrigName != p.Name {
130 s += ",name=" + p.OrigName
131 }
132 if len(p.Enum) > 0 {
133 s += ",enum=" + p.Enum
134 }
135 if len(p.Default) > 0 {
136 s += ",def=" + p.Default
137 }
138 return s
139}
140
141// Parse populates p by parsing a string in the "PB(...)" struct tag style.
142func (p *Properties) Parse(s string) {
143 // "bytes,49,opt,def=hello!,name=foo"
Rob Pike53385442010-06-30 22:22:43 -0700144 fields := strings.Split(s, ",", -1) // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700145 if len(fields) < 2 {
146 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
147 return
148 }
149
150 p.Wire = fields[0]
151 switch p.Wire {
152 case "varint":
153 p.WireType = WireVarint
154 p.valEnc = (*Buffer).EncodeVarint
155 p.valDec = (*Buffer).DecodeVarint
156 case "fixed32":
157 p.WireType = WireFixed32
158 p.valEnc = (*Buffer).EncodeFixed32
159 p.valDec = (*Buffer).DecodeFixed32
160 case "fixed64":
161 p.WireType = WireFixed64
162 p.valEnc = (*Buffer).EncodeFixed64
163 p.valDec = (*Buffer).DecodeFixed64
164 case "zigzag32":
165 p.WireType = WireVarint
166 p.valEnc = (*Buffer).EncodeZigzag32
167 p.valDec = (*Buffer).DecodeZigzag32
168 case "zigzag64":
169 p.WireType = WireVarint
170 p.valEnc = (*Buffer).EncodeZigzag64
171 p.valDec = (*Buffer).DecodeZigzag64
172 case "bytes", "group":
173 p.WireType = WireBytes
174 // no numeric converter for non-numeric types
175 default:
176 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
177 return
178 }
179
180 var err os.Error
181 p.Tag, err = strconv.Atoi(fields[1])
182 if err != nil {
183 return
184 }
185
186 for i := 2; i < len(fields); i++ {
187 f := fields[i]
188 switch {
189 case f == "req":
190 p.Required = true
191 case f == "opt":
192 p.Optional = true
193 case f == "rep":
194 p.Repeated = true
195 case len(f) >= 5 && f[0:5] == "name=":
196 p.OrigName = f[5:len(f)]
197 case len(f) >= 5 && f[0:5] == "enum=":
198 p.Enum = f[5:len(f)]
199 case len(f) >= 4 && f[0:4] == "def=":
200 p.Default = f[4:len(f)] // rest of string
201 if i+1 < len(fields) {
202 // Commas aren't escaped, and def is always last.
203 p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
204 break
205 }
206 }
207 }
208}
209
210// Initialize the fields for encoding and decoding.
211func (p *Properties) setEncAndDec(typ reflect.Type) {
212 var vbool bool
213 var vbyte byte
214 var vint32 int32
215 var vint64 int64
216 var vfloat32 float32
217 var vfloat64 float64
218 var vstring string
219 var vslice []byte
220
221 p.enc = nil
222 p.dec = nil
223
224 switch t1 := typ.(type) {
225 default:
226 fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
227 break
228
229 case *reflect.PtrType:
230 switch t2 := t1.Elem().(type) {
231 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700232 BadType:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700233 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
234 break
235 case *reflect.BoolType:
236 p.enc = (*Buffer).enc_bool
237 p.dec = (*Buffer).dec_bool
238 p.alignof = unsafe.Alignof(vbool)
239 p.sizeof = unsafe.Sizeof(vbool)
Rob Pikeab5b8022010-06-21 17:47:58 -0700240 case *reflect.IntType, *reflect.UintType:
241 switch t2.Bits() {
242 case 32:
243 p.enc = (*Buffer).enc_int32
244 p.dec = (*Buffer).dec_int32
245 p.alignof = unsafe.Alignof(vint32)
246 p.sizeof = unsafe.Sizeof(vint32)
247 case 64:
248 p.enc = (*Buffer).enc_int64
249 p.dec = (*Buffer).dec_int64
250 p.alignof = unsafe.Alignof(vint64)
251 p.sizeof = unsafe.Sizeof(vint64)
252 default:
253 goto BadType
254 }
255 case *reflect.FloatType:
256 switch t2.Bits() {
257 case 32:
258 p.enc = (*Buffer).enc_int32 // can just treat them as bits
259 p.dec = (*Buffer).dec_int32
260 p.alignof = unsafe.Alignof(vfloat32)
261 p.sizeof = unsafe.Sizeof(vfloat32)
262 case 64:
263 p.enc = (*Buffer).enc_int64 // can just treat them as bits
264 p.dec = (*Buffer).dec_int64
265 p.alignof = unsafe.Alignof(vfloat64)
266 p.sizeof = unsafe.Sizeof(vfloat64)
267 default:
268 goto BadType
269 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700270 case *reflect.StringType:
271 p.enc = (*Buffer).enc_string
272 p.dec = (*Buffer).dec_string
273 p.alignof = unsafe.Alignof(vstring)
274 p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
275 case *reflect.StructType:
276 p.stype = t1
277 if p.Wire == "bytes" {
278 p.enc = (*Buffer).enc_struct_message
279 p.dec = (*Buffer).dec_struct_message
280 } else {
281 p.enc = (*Buffer).enc_struct_group
282 p.dec = (*Buffer).dec_struct_group
283 }
284 }
285
286 case *reflect.SliceType:
287 switch t2 := t1.Elem().(type) {
288 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700289 BadSliceType:
290 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700291 break
Rob Pikeaaa3a622010-03-20 22:32:34 -0700292 case *reflect.BoolType:
293 p.enc = (*Buffer).enc_slice_bool
294 p.dec = (*Buffer).dec_slice_bool
295 p.alignof = unsafe.Alignof(vbool)
296 p.sizeof = startSize * unsafe.Sizeof(vbool)
Rob Pikeab5b8022010-06-21 17:47:58 -0700297 case *reflect.IntType, *reflect.UintType:
298 switch t2.Bits() {
299 case 32:
300 p.enc = (*Buffer).enc_slice_int32
301 p.dec = (*Buffer).dec_slice_int32
302 p.alignof = unsafe.Alignof(vint32)
303 p.sizeof = startSize * unsafe.Sizeof(vint32)
304 case 64:
305 p.enc = (*Buffer).enc_slice_int64
306 p.dec = (*Buffer).dec_slice_int64
307 p.alignof = unsafe.Alignof(vint64)
308 p.sizeof = startSize * unsafe.Sizeof(vint64)
309 case 8:
310 if t2.Kind() == reflect.Uint8 {
311 p.enc = (*Buffer).enc_slice_byte
312 p.dec = (*Buffer).dec_slice_byte
313 p.alignof = unsafe.Alignof(vbyte)
314 p.sizeof = startSize * unsafe.Sizeof(vbyte)
315 }
316 default:
317 goto BadSliceType
318 }
319 case *reflect.FloatType:
320 switch t2.Bits() {
321 case 32:
322 p.enc = (*Buffer).enc_slice_int32 // can just treat them as bits
323 p.dec = (*Buffer).dec_slice_int32
324 p.alignof = unsafe.Alignof(vfloat32)
325 p.sizeof = startSize * unsafe.Sizeof(vfloat32)
326 case 64:
327 p.enc = (*Buffer).enc_slice_int64 // can just treat them as bits
328 p.dec = (*Buffer).dec_slice_int64
329 p.alignof = unsafe.Alignof(vfloat64)
330 p.sizeof = startSize * unsafe.Sizeof(vfloat64)
331 default:
332 goto BadSliceType
333 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700334 case *reflect.StringType:
335 p.enc = (*Buffer).enc_slice_string
336 p.dec = (*Buffer).dec_slice_string
337 p.alignof = unsafe.Alignof(vstring)
338 p.sizeof = startSize * unsafe.Sizeof(vstring)
339 case *reflect.PtrType:
340 switch t3 := t2.Elem().(type) {
341 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700342 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700343 break
344 case *reflect.StructType:
345 p.stype = t2
346 p.enc = (*Buffer).enc_slice_struct_group
347 p.dec = (*Buffer).dec_slice_struct_group
348 if p.Wire == "bytes" {
349 p.enc = (*Buffer).enc_slice_struct_message
350 p.dec = (*Buffer).dec_slice_struct_message
351 }
352 p.alignof = unsafe.Alignof(vslice)
353 p.sizeof = startSize * unsafe.Sizeof(vslice)
354 }
355 case *reflect.SliceType:
Rob Pikeab5b8022010-06-21 17:47:58 -0700356 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700357 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700358 fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700359 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700360 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700361 p.enc = (*Buffer).enc_slice_slice_byte
362 p.dec = (*Buffer).dec_slice_slice_byte
363 p.alignof = unsafe.Alignof(vslice)
364 p.sizeof = startSize * unsafe.Sizeof(vslice)
365 }
366 }
367 }
368
369 // precalculate tag code
370 x := p.Tag<<3 | p.WireType
371 i := 0
372 for i = 0; x > 127; i++ {
373 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
374 x >>= 7
375 }
376 p.tagbuf[i] = uint8(x)
377 p.tagcode = p.tagbuf[0 : i+1]
378}
379
380// Init populates the properties from a protocol buffer struct field.
381func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
382 // "PB(bytes,49,opt,def=hello!)"
383 // TODO: should not assume the only thing is PB(...)
384 p.Name = name
385 p.OrigName = name
386 p.offset = offset
387
388 if len(tag) < 4 || tag[0:3] != "PB(" || tag[len(tag)-1] != ')' {
389 return
390 }
391 p.Parse(tag[3 : len(tag)-1])
392 p.setEncAndDec(typ)
393}
394
395var (
396 mutex sync.Mutex
397 propertiesMap = make(map[*reflect.StructType]*StructProperties)
398)
399
400// GetProperties returns the list of properties for the type represented by t.
401func GetProperties(t *reflect.StructType) *StructProperties {
402 mutex.Lock()
403 if prop, ok := propertiesMap[t]; ok {
404 mutex.Unlock()
405 stats.Chit++
406 return prop
407 }
408 stats.Cmiss++
409
410 prop := new(StructProperties)
411
412 // build properties
413 prop.Prop = make([]*Properties, t.NumField())
414 for i := 0; i < t.NumField(); i++ {
415 f := t.Field(i)
416 p := new(Properties)
417 p.Init(f.Type, f.Name, f.Tag, f.Offset)
418 if f.Name == "XXX_extensions" { // special case
419 var vmap map[int32][]byte
420 p.enc = (*Buffer).enc_map
421 p.dec = nil // not needed
422 p.alignof = unsafe.Alignof(vmap)
423 p.sizeof = unsafe.Sizeof(vmap)
424 }
425 prop.Prop[i] = p
426 if debug {
427 print(i, " ", f.Name, " ", t.String(), " ")
428 if p.Tag > 0 {
429 print(p.String())
430 }
431 print("\n")
432 }
433 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
434 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
435 }
436 }
437
438 // build required counts
439 // build scratch offsets
440 // build tags
441 reqCount := 0
442 scratch := uintptr(0)
443 prop.tags = make(map[int]int)
444 for i, p := range prop.Prop {
445 if p.Required {
446 reqCount++
447 }
448 scratch = align(scratch, p.alignof)
449 p.scratch = scratch
450 scratch += uintptr(p.sizeof)
451 prop.tags[p.Tag] = i
452 }
453 prop.reqCount = reqCount
454 prop.nscratch = scratch
455
456 propertiesMap[t] = prop
457 mutex.Unlock()
458 return prop
459}
460
461// Alignment of the data in the scratch area. It doesn't have to be
462// exact, just conservative. Returns the first number >= o that divides s.
463func align(o uintptr, s int) uintptr {
464 if s != 0 {
465 for o%uintptr(s) != 0 {
466 o++
467 }
468 }
469 return o
470}
471
472// Return the field index of the named field.
473// Returns nil if there is no such field.
474func fieldIndex(t *reflect.StructType, name string) []int {
475 if field, ok := t.FieldByName(name); ok {
476 return field.Index
477 }
478 return nil
479}
480
481// Return the Properties object for the x[0]'th field of the structure.
482func propByIndex(t *reflect.StructType, x []int) *Properties {
483 if len(x) != 1 {
484 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
485 return nil
486 }
487 prop := GetProperties(t)
488 return prop.Prop[x[0]]
489}
490
491// Get the address and type of a pointer to the structure from an interface.
492// unsafe.Reflect can do this, but does multiple mallocs.
493func getbase(pb interface{}) (t *reflect.PtrType, b uintptr, err os.Error) {
494 // get pointer
495 x := *(*[2]uintptr)(unsafe.Pointer(&pb))
496 b = x[1]
497 if b == 0 {
498 err = ErrNil
499 return
500 }
501
502 // get the reflect type of the struct.
503 t1 := unsafe.Typeof(pb).(*runtime.PtrType)
504 t = (*reflect.PtrType)(unsafe.Pointer(t1))
505 return
506}
507
508// Allocate the aux space containing all the decoded data. The structure
509// handed into Unmarshal is filled with pointers to this newly allocated
510// data.
511func getsbase(prop *StructProperties) uintptr {
512 var vbyteptr *byte
513 if prop.nscratch == 0 {
514 return 0
515 }
516
517 // allocate the decode space as pointers
518 // so that the GC will scan it for pointers
519 n := uintptr(unsafe.Sizeof(vbyteptr))
520 b := make([]*byte, (prop.nscratch+n-1)/n)
521 sbase := uintptr(unsafe.Pointer(&b[0]))
522 return sbase
523}
524
525// A global registry of enum types.
526// The generated code will register the generated maps by calling RegisterEnum.
527
528var enumNameMaps = make(map[string]map[int32]string)
529var enumValueMaps = make(map[string]map[string]int32)
530
531// RegisterEnum is called from the generated code to install the enum descriptor
532// maps into the global table to aid parsing ASCII protocol buffers.
533func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
534 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700535 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700536 }
537 enumNameMaps[typeName] = nameMap
538 enumValueMaps[typeName] = valueMap
539}