blob: 99ea31ae3e7d1542e7aadddd4f373f58dd08586e [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 {
Rob Pike97e934d2011-04-11 12:52:49 -0700229 err = p.enc_struct(t.Elem(), b)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700230 }
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
Rob Pike97e934d2011-04-11 12:52:49 -0700292// All protocol buffer fields are nillable, but be careful.
293func isNil(v reflect.Value) bool {
294 switch v.Kind() {
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700295 case reflect.Map, reflect.Ptr, reflect.Slice:
Rob Pike97e934d2011-04-11 12:52:49 -0700296 return v.IsNil()
297 }
298 return false
299}
300
Rob Pikeaaa3a622010-03-20 22:32:34 -0700301// Encode a message struct.
302func (o *Buffer) enc_struct_message(p *Properties, base uintptr) os.Error {
303 // Can the object marshal itself?
304 iv := unsafe.Unreflect(p.stype, unsafe.Pointer(base+p.offset))
305 if m, ok := iv.(Marshaler); ok {
Nigel Tao4ede8452011-04-28 11:27:25 +1000306 if isNil(reflect.ValueOf(iv)) {
David Symonds03c9d412010-08-26 14:23:18 +1000307 return ErrNil
308 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700309 data, err := m.Marshal()
310 if err != nil {
311 return err
312 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800313 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700314 o.EncodeRawBytes(data)
315 return nil
316 }
317 v := *(**struct{})(unsafe.Pointer(base + p.offset))
318 if v == nil {
319 return ErrNil
320 }
321
322 // need the length before we can write out the message itself,
323 // so marshal into a separate byte buffer first.
324 obuf := o.buf
325 o.buf = o.bufalloc()
326
327 b := uintptr(unsafe.Pointer(v))
Rob Pike97e934d2011-04-11 12:52:49 -0700328 typ := p.stype.Elem()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700329 err := o.enc_struct(typ, b)
330
331 nbuf := o.buf
332 o.buf = obuf
333 if err != nil {
334 o.buffree(nbuf)
335 return err
336 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800337 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700338 o.EncodeRawBytes(nbuf)
339 o.buffree(nbuf)
340 return nil
341}
342
343// Encode a group struct.
344func (o *Buffer) enc_struct_group(p *Properties, base uintptr) os.Error {
345 v := *(**struct{})(unsafe.Pointer(base + p.offset))
346 if v == nil {
347 return ErrNil
348 }
349
350 o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
351 b := uintptr(unsafe.Pointer(v))
Rob Pike97e934d2011-04-11 12:52:49 -0700352 typ := p.stype.Elem()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700353 err := o.enc_struct(typ, b)
354 if err != nil {
355 return err
356 }
357 o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
358 return nil
359}
360
361// Encode a slice of bools ([]bool).
362func (o *Buffer) enc_slice_bool(p *Properties, base uintptr) os.Error {
363 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
364 l := len(s)
365 if l == 0 {
366 return ErrNil
367 }
368 for _, x := range s {
Rob Pike99fa2b62010-12-02 10:39:42 -0800369 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700370 if x != 0 {
371 x = 1
372 }
373 p.valEnc(o, uint64(x))
374 }
375 return nil
376}
377
David Symonds5b7775e2010-12-01 10:09:04 +1100378// Encode a slice of bools ([]bool) in packed format.
379func (o *Buffer) enc_slice_packed_bool(p *Properties, base uintptr) os.Error {
380 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
381 l := len(s)
382 if l == 0 {
383 return ErrNil
384 }
385 o.buf = append(o.buf, p.tagcode...)
386 o.EncodeVarint(uint64(l)) // each bool takes exactly one byte
387 for _, x := range s {
388 if x != 0 {
389 x = 1
390 }
391 p.valEnc(o, uint64(x))
392 }
393 return nil
394}
395
Rob Pikeaaa3a622010-03-20 22:32:34 -0700396// Encode a slice of bytes ([]byte).
397func (o *Buffer) enc_slice_byte(p *Properties, base uintptr) os.Error {
398 s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
Mikkel Krautzdb488aa2010-11-29 14:15:51 -0800399 if s == nil {
400 return ErrNil
401 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800402 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700403 o.EncodeRawBytes(s)
404 return nil
405}
406
407// Encode a slice of int32s ([]int32).
408func (o *Buffer) enc_slice_int32(p *Properties, base uintptr) os.Error {
409 s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
410 l := len(s)
411 if l == 0 {
412 return ErrNil
413 }
414 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800415 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700416 x := s[i]
417 p.valEnc(o, uint64(x))
418 }
419 return nil
420}
421
David Symonds5b7775e2010-12-01 10:09:04 +1100422// Encode a slice of int32s ([]int32) in packed format.
423func (o *Buffer) enc_slice_packed_int32(p *Properties, base uintptr) os.Error {
424 s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
425 l := len(s)
426 if l == 0 {
427 return ErrNil
428 }
429 // TODO: Reuse a Buffer.
430 buf := NewBuffer(nil)
431 for i := 0; i < l; i++ {
432 p.valEnc(buf, uint64(s[i]))
433 }
434
435 o.buf = append(o.buf, p.tagcode...)
436 o.EncodeVarint(uint64(len(buf.buf)))
437 o.buf = append(o.buf, buf.buf...)
438 return nil
439}
440
Rob Pikeaaa3a622010-03-20 22:32:34 -0700441// Encode a slice of int64s ([]int64).
442func (o *Buffer) enc_slice_int64(p *Properties, base uintptr) os.Error {
443 s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
444 l := len(s)
445 if l == 0 {
446 return ErrNil
447 }
448 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800449 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700450 x := s[i]
451 p.valEnc(o, uint64(x))
452 }
453 return nil
454}
455
David Symonds5b7775e2010-12-01 10:09:04 +1100456// Encode a slice of int64s ([]int64) in packed format.
457func (o *Buffer) enc_slice_packed_int64(p *Properties, base uintptr) os.Error {
458 s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
459 l := len(s)
460 if l == 0 {
461 return ErrNil
462 }
463 // TODO: Reuse a Buffer.
464 buf := NewBuffer(nil)
465 for i := 0; i < l; i++ {
466 p.valEnc(buf, s[i])
467 }
468
469 o.buf = append(o.buf, p.tagcode...)
470 o.EncodeVarint(uint64(len(buf.buf)))
471 o.buf = append(o.buf, buf.buf...)
472 return nil
473}
474
Rob Pikeaaa3a622010-03-20 22:32:34 -0700475// Encode a slice of slice of bytes ([][]byte).
476func (o *Buffer) enc_slice_slice_byte(p *Properties, base uintptr) os.Error {
477 ss := *(*[][]uint8)(unsafe.Pointer(base + p.offset))
478 l := len(ss)
479 if l == 0 {
480 return ErrNil
481 }
482 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800483 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700484 s := ss[i]
485 o.EncodeRawBytes(s)
486 }
487 return nil
488}
489
490// Encode a slice of strings ([]string).
491func (o *Buffer) enc_slice_string(p *Properties, base uintptr) os.Error {
492 ss := *(*[]string)(unsafe.Pointer(base + p.offset))
493 l := len(ss)
494 for i := 0; i < l; i++ {
Rob Pike99fa2b62010-12-02 10:39:42 -0800495 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700496 s := ss[i]
497 o.EncodeStringBytes(s)
498 }
499 return nil
500}
501
502// Encode a slice of message structs ([]*struct).
503func (o *Buffer) enc_slice_struct_message(p *Properties, base uintptr) os.Error {
504 s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
505 l := len(s)
Rob Pike97e934d2011-04-11 12:52:49 -0700506 typ := p.stype.Elem()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700507
508 for i := 0; i < l; i++ {
509 v := s[i]
510 if v == nil {
511 return ErrRepeatedHasNil
512 }
513
514 // Can the object marshal itself?
515 iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&s[i]))
516 if m, ok := iv.(Marshaler); ok {
Nigel Tao4ede8452011-04-28 11:27:25 +1000517 if reflect.ValueOf(iv).IsNil() {
David Symonds03c9d412010-08-26 14:23:18 +1000518 return ErrNil
519 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700520 data, err := m.Marshal()
521 if err != nil {
522 return err
523 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800524 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700525 o.EncodeRawBytes(data)
526 continue
527 }
528
529 obuf := o.buf
530 o.buf = o.bufalloc()
531
532 b := uintptr(unsafe.Pointer(v))
533 err := o.enc_struct(typ, b)
534
535 nbuf := o.buf
536 o.buf = obuf
537 if err != nil {
538 o.buffree(nbuf)
539 if err == ErrNil {
540 return ErrRepeatedHasNil
541 }
542 return err
543 }
Rob Pike99fa2b62010-12-02 10:39:42 -0800544 o.buf = append(o.buf, p.tagcode...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 o.EncodeRawBytes(nbuf)
546
547 o.buffree(nbuf)
548 }
549 return nil
550}
551
552// Encode a slice of group structs ([]*struct).
553func (o *Buffer) enc_slice_struct_group(p *Properties, base uintptr) os.Error {
554 s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
555 l := len(s)
Rob Pike97e934d2011-04-11 12:52:49 -0700556 typ := p.stype.Elem()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700557
558 for i := 0; i < l; i++ {
559 v := s[i]
560 if v == nil {
561 return ErrRepeatedHasNil
562 }
563
564 o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
565
566 b := uintptr(unsafe.Pointer(v))
567 err := o.enc_struct(typ, b)
568
569 if err != nil {
570 if err == ErrNil {
571 return ErrRepeatedHasNil
572 }
573 return err
574 }
575
576 o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
577 }
578 return nil
579}
580
581// Encode an extension map.
582func (o *Buffer) enc_map(p *Properties, base uintptr) os.Error {
583 v := *(*map[int32][]byte)(unsafe.Pointer(base + p.offset))
584 for _, b := range v {
Rob Pike99fa2b62010-12-02 10:39:42 -0800585 o.buf = append(o.buf, b...)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700586 }
587 return nil
588}
589
590// Encode a struct.
Rob Pike97e934d2011-04-11 12:52:49 -0700591func (o *Buffer) enc_struct(t reflect.Type, base uintptr) os.Error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700592 prop := GetProperties(t)
593 required := prop.reqCount
594 for _, p := range prop.Prop {
595 if p.enc != nil {
596 err := p.enc(o, p, base)
597 if err != nil {
598 if err != ErrNil {
599 return err
600 }
601 } else if p.Required {
602 required--
603 }
604 }
605 }
606 // See if we encoded all required fields.
607 if required > 0 {
David Symonds5b7775e2010-12-01 10:09:04 +1100608 return &ErrRequiredNotSet{t}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700609 }
610
611 return nil
612}