blob: 960329a66df872ce3808331fbe9a41705f1cd2b6 [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"
144 fields := strings.Split(s, ",", 0) // breaks def=, but handled below.
145 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:
232 fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
233 break
234 case *reflect.BoolType:
235 p.enc = (*Buffer).enc_bool
236 p.dec = (*Buffer).dec_bool
237 p.alignof = unsafe.Alignof(vbool)
238 p.sizeof = unsafe.Sizeof(vbool)
239 case *reflect.Int32Type, *reflect.Uint32Type:
240 p.enc = (*Buffer).enc_int32
241 p.dec = (*Buffer).dec_int32
242 p.alignof = unsafe.Alignof(vint32)
243 p.sizeof = unsafe.Sizeof(vint32)
244 case *reflect.Int64Type, *reflect.Uint64Type:
245 p.enc = (*Buffer).enc_int64
246 p.dec = (*Buffer).dec_int64
247 p.alignof = unsafe.Alignof(vint64)
248 p.sizeof = unsafe.Sizeof(vint64)
249 case *reflect.Float32Type:
250 p.enc = (*Buffer).enc_int32 // can just treat them as bits
251 p.dec = (*Buffer).dec_int32
252 p.alignof = unsafe.Alignof(vfloat32)
253 p.sizeof = unsafe.Sizeof(vfloat32)
254 case *reflect.Float64Type:
255 p.enc = (*Buffer).enc_int64 // can just treat them as bits
256 p.dec = (*Buffer).dec_int64
257 p.alignof = unsafe.Alignof(vfloat64)
258 p.sizeof = unsafe.Sizeof(vfloat64)
259 case *reflect.StringType:
260 p.enc = (*Buffer).enc_string
261 p.dec = (*Buffer).dec_string
262 p.alignof = unsafe.Alignof(vstring)
263 p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
264 case *reflect.StructType:
265 p.stype = t1
266 if p.Wire == "bytes" {
267 p.enc = (*Buffer).enc_struct_message
268 p.dec = (*Buffer).dec_struct_message
269 } else {
270 p.enc = (*Buffer).enc_struct_group
271 p.dec = (*Buffer).dec_struct_group
272 }
273 }
274
275 case *reflect.SliceType:
276 switch t2 := t1.Elem().(type) {
277 default:
278 fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T\n", t1, t2)
279 break
280 case *reflect.Uint8Type:
281 p.enc = (*Buffer).enc_slice_byte
282 p.dec = (*Buffer).dec_slice_byte
283 p.alignof = unsafe.Alignof(vbyte)
284 p.sizeof = startSize * unsafe.Sizeof(vbyte)
285 case *reflect.BoolType:
286 p.enc = (*Buffer).enc_slice_bool
287 p.dec = (*Buffer).dec_slice_bool
288 p.alignof = unsafe.Alignof(vbool)
289 p.sizeof = startSize * unsafe.Sizeof(vbool)
290 case *reflect.Int32Type, *reflect.Uint32Type:
291 p.enc = (*Buffer).enc_slice_int32
292 p.dec = (*Buffer).dec_slice_int32
293 p.alignof = unsafe.Alignof(vint32)
294 p.sizeof = startSize * unsafe.Sizeof(vint32)
295 case *reflect.Int64Type, *reflect.Uint64Type:
296 p.enc = (*Buffer).enc_slice_int64
297 p.dec = (*Buffer).dec_slice_int64
298 p.alignof = unsafe.Alignof(vint64)
299 p.sizeof = startSize * unsafe.Sizeof(vint64)
300 case *reflect.Float32Type:
301 p.enc = (*Buffer).enc_slice_int32 // can just treat them as bits
302 p.dec = (*Buffer).dec_slice_int32
303 p.alignof = unsafe.Alignof(vfloat32)
304 p.sizeof = startSize * unsafe.Sizeof(vfloat32)
305 case *reflect.Float64Type:
306 p.enc = (*Buffer).enc_slice_int64 // can just treat them as bits
307 p.dec = (*Buffer).dec_slice_int64
308 p.alignof = unsafe.Alignof(vfloat64)
309 p.sizeof = startSize * unsafe.Sizeof(vfloat64)
310 case *reflect.StringType:
311 p.enc = (*Buffer).enc_slice_string
312 p.dec = (*Buffer).dec_slice_string
313 p.alignof = unsafe.Alignof(vstring)
314 p.sizeof = startSize * unsafe.Sizeof(vstring)
315 case *reflect.PtrType:
316 switch t3 := t2.Elem().(type) {
317 default:
318 fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T -> %T\n", t1, t2, t3)
319 break
320 case *reflect.StructType:
321 p.stype = t2
322 p.enc = (*Buffer).enc_slice_struct_group
323 p.dec = (*Buffer).dec_slice_struct_group
324 if p.Wire == "bytes" {
325 p.enc = (*Buffer).enc_slice_struct_message
326 p.dec = (*Buffer).dec_slice_struct_message
327 }
328 p.alignof = unsafe.Alignof(vslice)
329 p.sizeof = startSize * unsafe.Sizeof(vslice)
330 }
331 case *reflect.SliceType:
332 switch t3 := t2.Elem().(type) {
333 default:
334 fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T -> %T\n", t1, t2, t3)
335 break
336 case *reflect.Uint8Type:
337 p.enc = (*Buffer).enc_slice_slice_byte
338 p.dec = (*Buffer).dec_slice_slice_byte
339 p.alignof = unsafe.Alignof(vslice)
340 p.sizeof = startSize * unsafe.Sizeof(vslice)
341 }
342 }
343 }
344
345 // precalculate tag code
346 x := p.Tag<<3 | p.WireType
347 i := 0
348 for i = 0; x > 127; i++ {
349 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
350 x >>= 7
351 }
352 p.tagbuf[i] = uint8(x)
353 p.tagcode = p.tagbuf[0 : i+1]
354}
355
356// Init populates the properties from a protocol buffer struct field.
357func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
358 // "PB(bytes,49,opt,def=hello!)"
359 // TODO: should not assume the only thing is PB(...)
360 p.Name = name
361 p.OrigName = name
362 p.offset = offset
363
364 if len(tag) < 4 || tag[0:3] != "PB(" || tag[len(tag)-1] != ')' {
365 return
366 }
367 p.Parse(tag[3 : len(tag)-1])
368 p.setEncAndDec(typ)
369}
370
371var (
372 mutex sync.Mutex
373 propertiesMap = make(map[*reflect.StructType]*StructProperties)
374)
375
376// GetProperties returns the list of properties for the type represented by t.
377func GetProperties(t *reflect.StructType) *StructProperties {
378 mutex.Lock()
379 if prop, ok := propertiesMap[t]; ok {
380 mutex.Unlock()
381 stats.Chit++
382 return prop
383 }
384 stats.Cmiss++
385
386 prop := new(StructProperties)
387
388 // build properties
389 prop.Prop = make([]*Properties, t.NumField())
390 for i := 0; i < t.NumField(); i++ {
391 f := t.Field(i)
392 p := new(Properties)
393 p.Init(f.Type, f.Name, f.Tag, f.Offset)
394 if f.Name == "XXX_extensions" { // special case
395 var vmap map[int32][]byte
396 p.enc = (*Buffer).enc_map
397 p.dec = nil // not needed
398 p.alignof = unsafe.Alignof(vmap)
399 p.sizeof = unsafe.Sizeof(vmap)
400 }
401 prop.Prop[i] = p
402 if debug {
403 print(i, " ", f.Name, " ", t.String(), " ")
404 if p.Tag > 0 {
405 print(p.String())
406 }
407 print("\n")
408 }
409 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
410 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
411 }
412 }
413
414 // build required counts
415 // build scratch offsets
416 // build tags
417 reqCount := 0
418 scratch := uintptr(0)
419 prop.tags = make(map[int]int)
420 for i, p := range prop.Prop {
421 if p.Required {
422 reqCount++
423 }
424 scratch = align(scratch, p.alignof)
425 p.scratch = scratch
426 scratch += uintptr(p.sizeof)
427 prop.tags[p.Tag] = i
428 }
429 prop.reqCount = reqCount
430 prop.nscratch = scratch
431
432 propertiesMap[t] = prop
433 mutex.Unlock()
434 return prop
435}
436
437// Alignment of the data in the scratch area. It doesn't have to be
438// exact, just conservative. Returns the first number >= o that divides s.
439func align(o uintptr, s int) uintptr {
440 if s != 0 {
441 for o%uintptr(s) != 0 {
442 o++
443 }
444 }
445 return o
446}
447
448// Return the field index of the named field.
449// Returns nil if there is no such field.
450func fieldIndex(t *reflect.StructType, name string) []int {
451 if field, ok := t.FieldByName(name); ok {
452 return field.Index
453 }
454 return nil
455}
456
457// Return the Properties object for the x[0]'th field of the structure.
458func propByIndex(t *reflect.StructType, x []int) *Properties {
459 if len(x) != 1 {
460 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
461 return nil
462 }
463 prop := GetProperties(t)
464 return prop.Prop[x[0]]
465}
466
467// Get the address and type of a pointer to the structure from an interface.
468// unsafe.Reflect can do this, but does multiple mallocs.
469func getbase(pb interface{}) (t *reflect.PtrType, b uintptr, err os.Error) {
470 // get pointer
471 x := *(*[2]uintptr)(unsafe.Pointer(&pb))
472 b = x[1]
473 if b == 0 {
474 err = ErrNil
475 return
476 }
477
478 // get the reflect type of the struct.
479 t1 := unsafe.Typeof(pb).(*runtime.PtrType)
480 t = (*reflect.PtrType)(unsafe.Pointer(t1))
481 return
482}
483
484// Allocate the aux space containing all the decoded data. The structure
485// handed into Unmarshal is filled with pointers to this newly allocated
486// data.
487func getsbase(prop *StructProperties) uintptr {
488 var vbyteptr *byte
489 if prop.nscratch == 0 {
490 return 0
491 }
492
493 // allocate the decode space as pointers
494 // so that the GC will scan it for pointers
495 n := uintptr(unsafe.Sizeof(vbyteptr))
496 b := make([]*byte, (prop.nscratch+n-1)/n)
497 sbase := uintptr(unsafe.Pointer(&b[0]))
498 return sbase
499}
500
501// A global registry of enum types.
502// The generated code will register the generated maps by calling RegisterEnum.
503
504var enumNameMaps = make(map[string]map[int32]string)
505var enumValueMaps = make(map[string]map[string]int32)
506
507// RegisterEnum is called from the generated code to install the enum descriptor
508// maps into the global table to aid parsing ASCII protocol buffers.
509func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
510 if _, ok := enumNameMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700511 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700512 }
513 enumNameMaps[typeName] = nameMap
514 enumValueMaps[typeName] = valueMap
515}