blob: d7a560550eb16008ab4f4659444d4b58d27abcce [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 (
Rob Pikeaaa3a622010-03-20 22:32:34 -070039 "os"
40 "reflect"
41 "runtime"
42 "unsafe"
43)
44
45// ErrRequiredNotSet is the error returned if Marshal is called with
46// a protocol buffer struct whose required fields have not
Rob Pikec6d8e4a2010-07-28 15:34:32 -070047// all been initialized. It is also the error returned if Unmarshal is
48// called with an encoded protocol buffer that does not include all the
49// required fields.
David Symonds5b7775e2010-12-01 10:09:04 +110050type ErrRequiredNotSet struct {
51 t reflect.Type
52}
53
54func (e *ErrRequiredNotSet) String() string {
55 return "required fields not set in " + e.t.String()
56}
Rob Pikeaaa3a622010-03-20 22:32:34 -070057
58// ErrRepeatedHasNil is the error returned if Marshal is called with
59// a protocol buffer struct with a repeated field containing a nil element.
60var ErrRepeatedHasNil = os.NewError("repeated field has nil")
61
62// ErrNil is the error returned if Marshal is called with nil.
63var ErrNil = os.NewError("marshal called with nil")
64
65// The fundamental encoders that put bytes on the wire.
66// Those that take integer types all accept uint64 and are
67// therefore of type valueEncoder.
68
David Symonds4fee3b12010-11-11 10:00:13 +110069const maxVarintBytes = 10 // maximum length of a varint
70
Rob Pikeaaa3a622010-03-20 22:32:34 -070071// EncodeVarint returns the varint encoding of x.
72// This is the format for the
73// int32, int64, uint32, uint64, bool, and enum
74// protocol buffer types.
75// Not used by the package itself, but helpful to clients
76// wishing to use the same encoding.
77func EncodeVarint(x uint64) []byte {
David Symonds4fee3b12010-11-11 10:00:13 +110078 var buf [maxVarintBytes]byte
Rob Pikeaaa3a622010-03-20 22:32:34 -070079 var n int
80 for n = 0; x > 127; n++ {
81 buf[n] = 0x80 | uint8(x&0x7F)
82 x >>= 7
83 }
84 buf[n] = uint8(x)
85 n++
86 return buf[0:n]
87}
88
David Symonds4fee3b12010-11-11 10:00:13 +110089var emptyBytes [maxVarintBytes]byte
90
Rob Pikeaaa3a622010-03-20 22:32:34 -070091// EncodeVarint writes a varint-encoded integer to the Buffer.
92// This is the format for the
93// int32, int64, uint32, uint64, bool, and enum
94// protocol buffer types.
95func (p *Buffer) EncodeVarint(x uint64) os.Error {
96 l := len(p.buf)
David Symonds4fee3b12010-11-11 10:00:13 +110097 if l+maxVarintBytes > cap(p.buf) { // not necessary except for performance
98 p.buf = append(p.buf, emptyBytes[:]...)
99 } else {
100 p.buf = p.buf[:l+maxVarintBytes]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700101 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700102
David Symonds4fee3b12010-11-11 10:00:13 +1100103 for x >= 1<<7 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700104 p.buf[l] = uint8(x&0x7f | 0x80)
105 l++
106 x >>= 7
107 }
108 p.buf[l] = uint8(x)
David Symonds4fee3b12010-11-11 10:00:13 +1100109 p.buf = p.buf[:l+1]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700110 return nil
111}
112
113// EncodeFixed64 writes a 64-bit integer to the Buffer.
114// This is the format for the
115// fixed64, sfixed64, and double protocol buffer types.
116func (p *Buffer) EncodeFixed64(x uint64) os.Error {
David Symonds4fee3b12010-11-11 10:00:13 +1100117 const fixed64Bytes = 8
Rob Pikeaaa3a622010-03-20 22:32:34 -0700118 l := len(p.buf)
David Symonds4fee3b12010-11-11 10:00:13 +1100119 if l+fixed64Bytes > cap(p.buf) { // not necessary except for performance
120 p.buf = append(p.buf, emptyBytes[:fixed64Bytes]...)
121 } else {
122 p.buf = p.buf[:l+fixed64Bytes]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700124
125 p.buf[l] = uint8(x)
126 p.buf[l+1] = uint8(x >> 8)
127 p.buf[l+2] = uint8(x >> 16)
128 p.buf[l+3] = uint8(x >> 24)
129 p.buf[l+4] = uint8(x >> 32)
130 p.buf[l+5] = uint8(x >> 40)
131 p.buf[l+6] = uint8(x >> 48)
132 p.buf[l+7] = uint8(x >> 56)
133 return nil
134}
135
136// EncodeFixed32 writes a 32-bit integer to the Buffer.
137// This is the format for the
138// fixed32, sfixed32, and float protocol buffer types.
139func (p *Buffer) EncodeFixed32(x uint64) os.Error {
David Symonds4fee3b12010-11-11 10:00:13 +1100140 const fixed32Bytes = 4
Rob Pikeaaa3a622010-03-20 22:32:34 -0700141 l := len(p.buf)
David Symonds4fee3b12010-11-11 10:00:13 +1100142 if l+fixed32Bytes > cap(p.buf) { // not necessary except for performance
143 p.buf = append(p.buf, emptyBytes[:fixed32Bytes]...)
144 } else {
145 p.buf = p.buf[:l+fixed32Bytes]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700146 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700147
148 p.buf[l] = uint8(x)
149 p.buf[l+1] = uint8(x >> 8)
150 p.buf[l+2] = uint8(x >> 16)
151 p.buf[l+3] = uint8(x >> 24)
152 return nil
153}
154
155// EncodeZigzag64 writes a zigzag-encoded 64-bit integer
156// to the Buffer.
157// This is the format used for the sint64 protocol buffer type.
158func (p *Buffer) EncodeZigzag64(x uint64) os.Error {
159 // use signed number to get arithmetic right shift.
160 return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
161}
162
163// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
164// to the Buffer.
165// This is the format used for the sint32 protocol buffer type.
166func (p *Buffer) EncodeZigzag32(x uint64) os.Error {
167 // use signed number to get arithmetic right shift.
168 return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
169}
170
171// EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
172// This is the format used for the bytes protocol buffer
173// type and for embedded messages.
174func (p *Buffer) EncodeRawBytes(b []byte) os.Error {
175 lb := len(b)
176 p.EncodeVarint(uint64(lb))
Rob Pike99fa2b62010-12-02 10:39:42 -0800177 p.buf = append(p.buf, b...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700178 return nil
179}
180
181// EncodeStringBytes writes an encoded string to the Buffer.
182// This is the format used for the proto2 string type.
183func (p *Buffer) EncodeStringBytes(s string) os.Error {
184
185 // this works because strings and slices are the same.
186 y := *(*[]byte)(unsafe.Pointer(&s))
187 p.EncodeRawBytes(y)
188 return nil
189}
190
191// Marshaler is the interface representing objects that can marshal themselves.
192type Marshaler interface {
193 Marshal() ([]byte, os.Error)
194}
195
196// Marshal takes the protocol buffer struct represented by pb
197// and encodes it into the wire format, returning the data.
198func Marshal(pb interface{}) ([]byte, os.Error) {
199 // Can the object marshal itself?
200 if m, ok := pb.(Marshaler); ok {
201 return m.Marshal()
202 }
203 p := NewBuffer(nil)
204 err := p.Marshal(pb)
205 if err != nil {
206 return nil, err
207 }
208 return p.buf, err
209}
210
211// Marshal takes the protocol buffer struct represented by pb
212// and encodes it into the wire format, writing the result to the
213// Buffer.
214func (p *Buffer) Marshal(pb interface{}) os.Error {
215 // Can the object marshal itself?
216 if m, ok := pb.(Marshaler); ok {
217 data, err := m.Marshal()
218 if err != nil {
219 return err
220 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800221 p.buf = append(p.buf, data...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700222 return nil
223 }
224
225 mstat := runtime.MemStats.Mallocs
226
227 t, b, err := getbase(pb)
228 if err == nil {
229 err = p.enc_struct(t.Elem().(*reflect.StructType), b)
230 }
231
232 mstat = runtime.MemStats.Mallocs - mstat
233 stats.Emalloc += mstat
234 stats.Encode++
235
236 return err
237}
238
239// Individual type encoders.
240
241// Encode a bool.
242func (o *Buffer) enc_bool(p *Properties, base uintptr) os.Error {
243 v := *(**uint8)(unsafe.Pointer(base + p.offset))
244 if v == nil {
245 return ErrNil
246 }
247 x := *v
248 if x != 0 {
249 x = 1
250 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800251 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700252 p.valEnc(o, uint64(x))
253 return nil
254}
255
256// Encode an int32.
257func (o *Buffer) enc_int32(p *Properties, base uintptr) os.Error {
258 v := *(**uint32)(unsafe.Pointer(base + p.offset))
259 if v == nil {
260 return ErrNil
261 }
262 x := *v
Rob Pike99fa2b62010-12-02 10:39:42 -0800263 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700264 p.valEnc(o, uint64(x))
265 return nil
266}
267
268// Encode an int64.
269func (o *Buffer) enc_int64(p *Properties, base uintptr) os.Error {
270 v := *(**uint64)(unsafe.Pointer(base + p.offset))
271 if v == nil {
272 return ErrNil
273 }
274 x := *v
Rob Pike99fa2b62010-12-02 10:39:42 -0800275 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700276 p.valEnc(o, uint64(x))
277 return nil
278}
279
280// Encode a string.
281func (o *Buffer) enc_string(p *Properties, base uintptr) os.Error {
282 v := *(**string)(unsafe.Pointer(base + p.offset))
283 if v == nil {
284 return ErrNil
285 }
286 x := *v
Rob Pike99fa2b62010-12-02 10:39:42 -0800287 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288 o.EncodeStringBytes(x)
289 return nil
290}
291
292// Encode a message struct.
293func (o *Buffer) enc_struct_message(p *Properties, base uintptr) os.Error {
294 // Can the object marshal itself?
295 iv := unsafe.Unreflect(p.stype, unsafe.Pointer(base+p.offset))
296 if m, ok := iv.(Marshaler); ok {
David Symonds03c9d412010-08-26 14:23:18 +1000297 if n, ok := reflect.NewValue(iv).(nillable); ok && n.IsNil() {
298 return ErrNil
299 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700300 data, err := m.Marshal()
301 if err != nil {
302 return err
303 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800304 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700305 o.EncodeRawBytes(data)
306 return nil
307 }
308 v := *(**struct{})(unsafe.Pointer(base + p.offset))
309 if v == nil {
310 return ErrNil
311 }
312
313 // need the length before we can write out the message itself,
314 // so marshal into a separate byte buffer first.
315 obuf := o.buf
316 o.buf = o.bufalloc()
317
318 b := uintptr(unsafe.Pointer(v))
319 typ := p.stype.Elem().(*reflect.StructType)
320 err := o.enc_struct(typ, b)
321
322 nbuf := o.buf
323 o.buf = obuf
324 if err != nil {
325 o.buffree(nbuf)
326 return err
327 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800328 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700329 o.EncodeRawBytes(nbuf)
330 o.buffree(nbuf)
331 return nil
332}
333
334// Encode a group struct.
335func (o *Buffer) enc_struct_group(p *Properties, base uintptr) os.Error {
336 v := *(**struct{})(unsafe.Pointer(base + p.offset))
337 if v == nil {
338 return ErrNil
339 }
340
341 o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
342 b := uintptr(unsafe.Pointer(v))
343 typ := p.stype.Elem().(*reflect.StructType)
344 err := o.enc_struct(typ, b)
345 if err != nil {
346 return err
347 }
348 o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
349 return nil
350}
351
352// Encode a slice of bools ([]bool).
353func (o *Buffer) enc_slice_bool(p *Properties, base uintptr) os.Error {
354 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
355 l := len(s)
356 if l == 0 {
357 return ErrNil
358 }
359 for _, x := range s {
Rob Pike99fa2b62010-12-02 10:39:42 -0800360 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700361 if x != 0 {
362 x = 1
363 }
364 p.valEnc(o, uint64(x))
365 }
366 return nil
367}
368
David Symonds5b7775e2010-12-01 10:09:04 +1100369// Encode a slice of bools ([]bool) in packed format.
370func (o *Buffer) enc_slice_packed_bool(p *Properties, base uintptr) os.Error {
371 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
372 l := len(s)
373 if l == 0 {
374 return ErrNil
375 }
376 o.buf = append(o.buf, p.tagcode...)
377 o.EncodeVarint(uint64(l)) // each bool takes exactly one byte
378 for _, x := range s {
379 if x != 0 {
380 x = 1
381 }
382 p.valEnc(o, uint64(x))
383 }
384 return nil
385}
386
Rob Pikeaaa3a622010-03-20 22:32:34 -0700387// Encode a slice of bytes ([]byte).
388func (o *Buffer) enc_slice_byte(p *Properties, base uintptr) os.Error {
389 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
Mikkel Krautzdb488aa2010-11-29 14:15:51 -0800390 if s == nil {
391 return ErrNil
392 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800393 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700394 o.EncodeRawBytes(s)
395 return nil
396}
397
398// Encode a slice of int32s ([]int32).
399func (o *Buffer) enc_slice_int32(p *Properties, base uintptr) os.Error {
400 s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
401 l := len(s)
402 if l == 0 {
403 return ErrNil
404 }
405 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800406 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700407 x := s[i]
408 p.valEnc(o, uint64(x))
409 }
410 return nil
411}
412
David Symonds5b7775e2010-12-01 10:09:04 +1100413// Encode a slice of int32s ([]int32) in packed format.
414func (o *Buffer) enc_slice_packed_int32(p *Properties, base uintptr) os.Error {
415 s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
416 l := len(s)
417 if l == 0 {
418 return ErrNil
419 }
420 // TODO: Reuse a Buffer.
421 buf := NewBuffer(nil)
422 for i := 0; i < l; i++ {
423 p.valEnc(buf, uint64(s[i]))
424 }
425
426 o.buf = append(o.buf, p.tagcode...)
427 o.EncodeVarint(uint64(len(buf.buf)))
428 o.buf = append(o.buf, buf.buf...)
429 return nil
430}
431
Rob Pikeaaa3a622010-03-20 22:32:34 -0700432// Encode a slice of int64s ([]int64).
433func (o *Buffer) enc_slice_int64(p *Properties, base uintptr) os.Error {
434 s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
435 l := len(s)
436 if l == 0 {
437 return ErrNil
438 }
439 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800440 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700441 x := s[i]
442 p.valEnc(o, uint64(x))
443 }
444 return nil
445}
446
David Symonds5b7775e2010-12-01 10:09:04 +1100447// Encode a slice of int64s ([]int64) in packed format.
448func (o *Buffer) enc_slice_packed_int64(p *Properties, base uintptr) os.Error {
449 s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
450 l := len(s)
451 if l == 0 {
452 return ErrNil
453 }
454 // TODO: Reuse a Buffer.
455 buf := NewBuffer(nil)
456 for i := 0; i < l; i++ {
457 p.valEnc(buf, s[i])
458 }
459
460 o.buf = append(o.buf, p.tagcode...)
461 o.EncodeVarint(uint64(len(buf.buf)))
462 o.buf = append(o.buf, buf.buf...)
463 return nil
464}
465
Rob Pikeaaa3a622010-03-20 22:32:34 -0700466// Encode a slice of slice of bytes ([][]byte).
467func (o *Buffer) enc_slice_slice_byte(p *Properties, base uintptr) os.Error {
468 ss := *(*[][]uint8)(unsafe.Pointer(base + p.offset))
469 l := len(ss)
470 if l == 0 {
471 return ErrNil
472 }
473 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800474 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700475 s := ss[i]
476 o.EncodeRawBytes(s)
477 }
478 return nil
479}
480
481// Encode a slice of strings ([]string).
482func (o *Buffer) enc_slice_string(p *Properties, base uintptr) os.Error {
483 ss := *(*[]string)(unsafe.Pointer(base + p.offset))
484 l := len(ss)
485 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800486 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700487 s := ss[i]
488 o.EncodeStringBytes(s)
489 }
490 return nil
491}
492
493// Encode a slice of message structs ([]*struct).
494func (o *Buffer) enc_slice_struct_message(p *Properties, base uintptr) os.Error {
495 s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
496 l := len(s)
497 typ := p.stype.Elem().(*reflect.StructType)
498
499 for i := 0; i < l; i++ {
500 v := s[i]
501 if v == nil {
502 return ErrRepeatedHasNil
503 }
504
505 // Can the object marshal itself?
506 iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&s[i]))
507 if m, ok := iv.(Marshaler); ok {
David Symonds03c9d412010-08-26 14:23:18 +1000508 if n, ok := reflect.NewValue(iv).(nillable); ok && n.IsNil() {
509 return ErrNil
510 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700511 data, err := m.Marshal()
512 if err != nil {
513 return err
514 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800515 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700516 o.EncodeRawBytes(data)
517 continue
518 }
519
520 obuf := o.buf
521 o.buf = o.bufalloc()
522
523 b := uintptr(unsafe.Pointer(v))
524 err := o.enc_struct(typ, b)
525
526 nbuf := o.buf
527 o.buf = obuf
528 if err != nil {
529 o.buffree(nbuf)
530 if err == ErrNil {
531 return ErrRepeatedHasNil
532 }
533 return err
534 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800535 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700536 o.EncodeRawBytes(nbuf)
537
538 o.buffree(nbuf)
539 }
540 return nil
541}
542
543// Encode a slice of group structs ([]*struct).
544func (o *Buffer) enc_slice_struct_group(p *Properties, base uintptr) os.Error {
545 s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
546 l := len(s)
547 typ := p.stype.Elem().(*reflect.StructType)
548
549 for i := 0; i < l; i++ {
550 v := s[i]
551 if v == nil {
552 return ErrRepeatedHasNil
553 }
554
555 o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
556
557 b := uintptr(unsafe.Pointer(v))
558 err := o.enc_struct(typ, b)
559
560 if err != nil {
561 if err == ErrNil {
562 return ErrRepeatedHasNil
563 }
564 return err
565 }
566
567 o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
568 }
569 return nil
570}
571
572// Encode an extension map.
573func (o *Buffer) enc_map(p *Properties, base uintptr) os.Error {
574 v := *(*map[int32][]byte)(unsafe.Pointer(base + p.offset))
575 for _, b := range v {
Rob Pike99fa2b62010-12-02 10:39:42 -0800576 o.buf = append(o.buf, b...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700577 }
578 return nil
579}
580
581// Encode a struct.
582func (o *Buffer) enc_struct(t *reflect.StructType, base uintptr) os.Error {
583 prop := GetProperties(t)
584 required := prop.reqCount
585 for _, p := range prop.Prop {
586 if p.enc != nil {
587 err := p.enc(o, p, base)
588 if err != nil {
589 if err != ErrNil {
590 return err
591 }
592 } else if p.Required {
593 required--
594 }
595 }
596 }
597 // See if we encoded all required fields.
598 if required > 0 {
David Symonds5b7775e2010-12-01 10:09:04 +1100599 return &ErrRequiredNotSet{t}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700600 }
601
602 return nil
603}