blob: 9b780f7d8b886a8b83995ce9b390b6138a464c1a [file] [log] [blame]
Christian Lavoieafc6d8f2011-02-20 02:39:19 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package thrift
21
22import (
23 "container/vector"
24 "encoding/binary"
25 "fmt"
26 "math"
27 "os"
28 "strings"
29)
30
31const (
32 COMPACT_PROTOCOL_ID = 0x082
33 COMPACT_VERSION = 1
34 COMPACT_VERSION_MASK = 0x1f
35 COMPACT_TYPE_MASK = 0x0E0
36 COMPACT_TYPE_SHIFT_AMOUNT = 5
37)
38
39type TCompactType byte
40
41const (
42 COMPACT_BOOLEAN_TRUE = 0x01
43 COMPACT_BOOLEAN_FALSE = 0x02
44 COMPACT_BYTE = 0x03
45 COMPACT_I16 = 0x04
46 COMPACT_I32 = 0x05
47 COMPACT_I64 = 0x06
48 COMPACT_DOUBLE = 0x07
49 COMPACT_BINARY = 0x08
50 COMPACT_LIST = 0x09
51 COMPACT_SET = 0x0A
52 COMPACT_MAP = 0x0B
53 COMPACT_STRUCT = 0x0C
54)
55
56var (
57 _TTypeToCompactType []TCompactType
58 _TSTOP TField
59)
60
61func init() {
62 _TSTOP = NewTField("", STOP, 0)
63 _TTypeToCompactType = make([]TCompactType, int(UTF16)+1)
64 _TTypeToCompactType[int(STOP)] = STOP
65 _TTypeToCompactType[int(BOOL)] = COMPACT_BOOLEAN_TRUE
66 _TTypeToCompactType[int(BYTE)] = COMPACT_BYTE
67 _TTypeToCompactType[int(I16)] = COMPACT_I16
68 _TTypeToCompactType[int(I32)] = COMPACT_I32
69 _TTypeToCompactType[int(I64)] = COMPACT_I64
70 _TTypeToCompactType[int(DOUBLE)] = COMPACT_DOUBLE
71 _TTypeToCompactType[int(STRING)] = COMPACT_BINARY
72 _TTypeToCompactType[int(LIST)] = COMPACT_LIST
73 _TTypeToCompactType[int(SET)] = COMPACT_SET
74 _TTypeToCompactType[int(MAP)] = COMPACT_MAP
75 _TTypeToCompactType[int(STRUCT)] = COMPACT_STRUCT
76}
77
78type TCompactProtocolFactory struct{}
79
80func NewTCompactProtocolFactory() *TCompactProtocolFactory {
81 return &TCompactProtocolFactory{}
82}
83
84func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol {
85 return NewTCompactProtocol(trans)
86}
87
88type TCompactProtocol struct {
89 trans TTransport
90
91 /**
92 * Used to keep track of the last field for the current and previous structs,
93 * so we can do the delta stuff.
94 */
95 lastField *vector.IntVector
96 lastFieldId int
97
98 /**
99 * If we encounter a boolean field begin, save the TField here so it can
100 * have the value incorporated.
101 */
102 booleanField TField
103
104 /**
105 * If we read a field header, and it's a boolean field, save the boolean
106 * value here so that readBool can use it.
107 */
108 boolValue bool
109 boolValueIsNotNull bool
110}
111
112/**
113 * Create a TCompactProtocol.
114 *
115 * @param transport the TTransport object to read from or write to.
116 */
117func NewTCompactProtocol(trans TTransport) *TCompactProtocol {
118 return &TCompactProtocol{trans: trans, lastField: &vector.IntVector{}}
119}
120
121
122//
123// Public Writing methods.
124//
125
126/**
127 * Write a message header to the wire. Compact Protocol messages contain the
128 * protocol version so we can migrate forwards in the future if need be.
129 */
130func (p *TCompactProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) TProtocolException {
131 _, err := p.writeByteDirect(COMPACT_PROTOCOL_ID)
132 if err != nil {
133 return NewTProtocolExceptionFromOsError(err)
134 }
135 _, err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK))
136 if err != nil {
137 return NewTProtocolExceptionFromOsError(err)
138 }
139 _, err = p.writeVarint32(seqid)
140 if err != nil {
141 return NewTProtocolExceptionFromOsError(err)
142 }
143 e := p.WriteString(name)
144 return e
145
146}
147
148func (p *TCompactProtocol) WriteMessageEnd() TProtocolException { return nil }
149
150/**
151 * Write a struct begin. This doesn't actually put anything on the wire. We
152 * use it as an opportunity to put special placeholder markers on the field
153 * stack so we can get the field id deltas correct.
154 */
155func (p *TCompactProtocol) WriteStructBegin(name string) TProtocolException {
156 p.lastField.Push(p.lastFieldId)
157 p.lastFieldId = 0
158 return nil
159}
160
161/**
162 * Write a struct end. This doesn't actually put anything on the wire. We use
163 * this as an opportunity to pop the last field from the current struct off
164 * of the field stack.
165 */
166func (p *TCompactProtocol) WriteStructEnd() TProtocolException {
167 p.lastFieldId = p.lastField.Pop()
168 return nil
169}
170
171func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
172 if typeId == BOOL {
173 // we want to possibly include the value, so we'll wait.
174 p.booleanField = NewTField(name, typeId, int(id))
175 return nil
176 }
177 _, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF)
178 return NewTProtocolExceptionFromOsError(err)
179}
180
181
182/**
183 * The workhorse of writeFieldBegin. It has the option of doing a
184 * 'type override' of the type header. This is used specifically in the
185 * boolean field case.
186 */
187func (p *TCompactProtocol) writeFieldBeginInternal(name string, typeId TType, id int16, typeOverride byte) (int, os.Error) {
188 // short lastField = lastField_.pop();
189
190 // if there's a type override, use that.
191 var typeToWrite byte
192 if typeOverride == 0xFF {
193 typeToWrite = byte(p.getCompactType(typeId))
194 } else {
195 typeToWrite = typeOverride
196 }
197 // check if we can use delta encoding for the field id
198 fieldId := int(id)
199 written := 0
200 if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 {
201 // write them together
202 written, err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite)
203 if err != nil {
204 return written, err
205 }
206 } else {
207 // write them separate
208 n, err := p.writeByteDirect(typeToWrite)
209 if err != nil {
210 return n, err
211 }
212 err = p.WriteI16(id)
213 written = n + 2
214 if err != nil {
215 return written, err
216 }
217 }
218
219 p.lastFieldId = fieldId
220 // p.lastField.Push(field.id);
221 return written, nil
222}
223
224
225func (p *TCompactProtocol) WriteFieldEnd() TProtocolException { return nil }
226
227func (p *TCompactProtocol) WriteFieldStop() TProtocolException {
228 _, err := p.writeByteDirect(STOP)
229 return NewTProtocolExceptionFromOsError(err)
230}
231
232func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
233 if size == 0 {
234 _, err := p.writeByteDirect(0)
235 return NewTProtocolExceptionFromOsError(err)
236 }
237 _, err := p.writeVarint32(int32(size))
238 if err != nil {
239 return NewTProtocolExceptionFromOsError(err)
240 }
241 _, err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType)))
242 return NewTProtocolExceptionFromOsError(err)
243}
244
245func (p *TCompactProtocol) WriteMapEnd() TProtocolException { return nil }
246
247/**
248 * Write a list header.
249 */
250func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
251 _, err := p.writeCollectionBegin(elemType, size)
252 return NewTProtocolExceptionFromOsError(err)
253}
254
255func (p *TCompactProtocol) WriteListEnd() TProtocolException { return nil }
256
257/**
258 * Write a set header.
259 */
260func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
261 _, err := p.writeCollectionBegin(elemType, size)
262 return NewTProtocolExceptionFromOsError(err)
263}
264
265func (p *TCompactProtocol) WriteSetEnd() TProtocolException { return nil }
266
267func (p *TCompactProtocol) WriteBool(value bool) TProtocolException {
268 v := byte(COMPACT_BOOLEAN_FALSE)
269 if value {
270 v = byte(COMPACT_BOOLEAN_TRUE)
271 }
272 if p.booleanField != nil {
273 // we haven't written the field header yet
274 _, err := p.writeFieldBeginInternal(p.booleanField.Name(), p.booleanField.TypeId(), int16(p.booleanField.Id()), v)
275 p.booleanField = nil
276 return NewTProtocolExceptionFromOsError(err)
277 }
278 // we're not part of a field, so just write the value.
279 _, err := p.writeByteDirect(v)
280 return NewTProtocolExceptionFromOsError(err)
281}
282
283/**
284 * Write a byte. Nothing to see here!
285 */
286func (p *TCompactProtocol) WriteByte(value byte) TProtocolException {
287 _, err := p.writeByteDirect(value)
288 return NewTProtocolExceptionFromOsError(err)
289}
290
291/**
292 * Write an I16 as a zigzag varint.
293 */
294func (p *TCompactProtocol) WriteI16(value int16) TProtocolException {
295 _, err := p.writeVarint32(p.int32ToZigzag(int32(value)))
296 return NewTProtocolExceptionFromOsError(err)
297}
298
299/**
300 * Write an i32 as a zigzag varint.
301 */
302func (p *TCompactProtocol) WriteI32(value int32) TProtocolException {
303 _, err := p.writeVarint32(p.int32ToZigzag(value))
304 return NewTProtocolExceptionFromOsError(err)
305}
306
307/**
308 * Write an i64 as a zigzag varint.
309 */
310func (p *TCompactProtocol) WriteI64(value int64) TProtocolException {
311 _, err := p.writeVarint64(p.int64ToZigzag(value))
312 return NewTProtocolExceptionFromOsError(err)
313}
314
315/**
316 * Write a double to the wire as 8 bytes.
317 */
318func (p *TCompactProtocol) WriteDouble(value float64) TProtocolException {
319 buf := make([]byte, 8)
320 binary.LittleEndian.PutUint64(buf, math.Float64bits(value))
321 _, err := p.trans.Write(buf)
322 return NewTProtocolExceptionFromOsError(err)
323}
324
325/**
326 * Write a string to the wire with a varint size preceeding.
327 */
328func (p *TCompactProtocol) WriteString(value string) TProtocolException {
329 buf := make([]byte, len(value))
330 strings.NewReader(value).Read(buf)
331 return p.WriteBinary(buf)
332}
333
334/**
335 * Write a byte array, using a varint for the size.
336 */
337func (p *TCompactProtocol) WriteBinary(bin []byte) TProtocolException {
338 _, e := p.writeVarint32(int32(len(bin)))
339 if e != nil {
340 return NewTProtocolExceptionFromOsError(e)
341 }
342 if len(bin) > 0 {
343 _, e = p.trans.Write(bin)
344 return NewTProtocolExceptionFromOsError(e)
345 }
346 return nil
347}
348
349
350//
351// Reading methods.
352//
353
354/**
355 * Read a message header.
356 */
357func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
358 protocolId, err := p.ReadByte()
359 if protocolId != COMPACT_PROTOCOL_ID {
360 s := fmt.Sprintf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId)
361 return "", typeId, seqId, NewTProtocolException(BAD_VERSION, s)
362 }
363 versionAndType, err := p.ReadByte()
364 version := versionAndType & COMPACT_VERSION_MASK
365 typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & 0x03)
366 if err != nil {
367 return
368 }
369 if version != COMPACT_VERSION {
370 s := fmt.Sprintf("Expected version %02x but got %02x", COMPACT_VERSION, version)
371 err = NewTProtocolException(BAD_VERSION, s)
372 return
373 }
374 seqId, e := p.readVarint32()
375 if e != nil {
376 err = NewTProtocolExceptionFromOsError(e)
377 return
378 }
379 name, err = p.ReadString()
380 return
381}
382
383func (p *TCompactProtocol) ReadMessageEnd() TProtocolException { return nil }
384
385/**
386 * Read a struct begin. There's nothing on the wire for this, but it is our
387 * opportunity to push a new struct begin marker onto the field stack.
388 */
389func (p *TCompactProtocol) ReadStructBegin() (name string, err TProtocolException) {
390 p.lastField.Push(p.lastFieldId)
391 p.lastFieldId = 0
392 return
393}
394
395/**
396 * Doesn't actually consume any wire data, just removes the last field for
397 * this struct from the field stack.
398 */
399func (p *TCompactProtocol) ReadStructEnd() TProtocolException {
400 // consume the last field we read off the wire.
401 p.lastFieldId = p.lastField.Pop()
402 return nil
403}
404
405/**
406 * Read a field header off the wire.
407 */
408func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err TProtocolException) {
409 t, err := p.ReadByte()
410 if err != nil {
411 return
412 }
413
414 // if it's a stop, then we can return immediately, as the struct is over.
415 if (t & 0x0f) == STOP {
416 return _TSTOP.Name(), _TSTOP.TypeId(), int16(_TSTOP.Id()), nil
417 }
418
419 // mask off the 4 MSB of the type header. it could contain a field id delta.
420 modifier := int16((t & 0xf0) >> 4)
421 if modifier == 0 {
422 // not a delta. look ahead for the zigzag varint field id.
423 id, err = p.ReadI16()
424 if err != nil {
425 return
426 }
427 } else {
428 // has a delta. add the delta to the last read field id.
429 id = int16(p.lastFieldId) + modifier
430 }
431 typeId, e := p.getTType(TCompactType(t & 0x0f))
432 if e != nil {
433 err = NewTProtocolExceptionFromOsError(e)
434 return
435 }
436
437 // if this happens to be a boolean field, the value is encoded in the type
438 if p.isBoolType(t) {
439 // save the boolean value in a special instance variable.
440 p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE)
441 p.boolValueIsNotNull = true
442 }
443
444 // push the new field onto the field stack so we can keep the deltas going.
445 p.lastFieldId = int(id)
446 return
447}
448
449func (p *TCompactProtocol) ReadFieldEnd() TProtocolException { return nil }
450
451/**
452 * Read a map header off the wire. If the size is zero, skip reading the key
453 * and value type. This means that 0-length maps will yield TMaps without the
454 * "correct" types.
455 */
456func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err TProtocolException) {
457 size32, e := p.readVarint32()
458 size = int(size32)
459 if e != nil {
460 err = NewTProtocolExceptionFromOsError(e)
461 return
462 }
463 keyAndValueType := byte(STOP)
464 if size != 0 {
465 keyAndValueType, err = p.ReadByte()
466 if err != nil {
467 return
468 }
469 }
470 keyType, _ = p.getTType(TCompactType(keyAndValueType >> 4))
471 valueType, _ = p.getTType(TCompactType(keyAndValueType & 0xf))
472 return
473}
474
475func (p *TCompactProtocol) ReadMapEnd() TProtocolException { return nil }
476
477/**
478 * Read a list header off the wire. If the list size is 0-14, the size will
479 * be packed into the element type header. If it's a longer list, the 4 MSB
480 * of the element type header will be 0xF, and a varint will follow with the
481 * true size.
482 */
483func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err TProtocolException) {
484 size_and_type, err := p.ReadByte()
485 if err != nil {
486 return
487 }
488 size = int((size_and_type >> 4) & 0x0f)
489 if size == 15 {
490 size2, e := p.readVarint32()
491 if e != nil {
492 err = NewTProtocolExceptionFromOsError(e)
493 return
494 }
495 size = int(size2)
496 }
497 elemType, e := p.getTType(TCompactType(size_and_type))
498 if e != nil {
499 err = NewTProtocolExceptionFromOsError(e)
500 return
501 }
502 return
503}
504
505func (p *TCompactProtocol) ReadListEnd() TProtocolException { return nil }
506
507/**
508 * Read a set header off the wire. If the set size is 0-14, the size will
509 * be packed into the element type header. If it's a longer set, the 4 MSB
510 * of the element type header will be 0xF, and a varint will follow with the
511 * true size.
512 */
513func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err TProtocolException) {
514 return p.ReadListBegin()
515}
516
517func (p *TCompactProtocol) ReadSetEnd() TProtocolException { return nil }
518
519/**
520 * Read a boolean off the wire. If this is a boolean field, the value should
521 * already have been read during readFieldBegin, so we'll just consume the
522 * pre-stored value. Otherwise, read a byte.
523 */
524func (p *TCompactProtocol) ReadBool() (value bool, err TProtocolException) {
525 if p.boolValueIsNotNull {
526 p.boolValueIsNotNull = false
527 return p.boolValue, nil
528 }
529 v, err := p.ReadByte()
530 return v == COMPACT_BOOLEAN_TRUE, err
531}
532
533/**
534 * Read a single byte off the wire. Nothing interesting here.
535 */
536func (p *TCompactProtocol) ReadByte() (value byte, err TProtocolException) {
537 buf := []byte{0}
538 _, e := p.trans.ReadAll(buf)
539 if e != nil {
540 return 0, NewTProtocolExceptionFromOsError(e)
541 }
542 return buf[0], nil
543}
544
545/**
546 * Read an i16 from the wire as a zigzag varint.
547 */
548func (p *TCompactProtocol) ReadI16() (value int16, err TProtocolException) {
549 v, err := p.ReadI32()
550 return int16(v), err
551}
552
553/**
554 * Read an i32 from the wire as a zigzag varint.
555 */
556func (p *TCompactProtocol) ReadI32() (value int32, err TProtocolException) {
557 v, e := p.readVarint32()
558 if e != nil {
559 return 0, NewTProtocolExceptionFromOsError(e)
560 }
561 value = p.zigzagToInt32(v)
562 return value, nil
563}
564
565/**
566 * Read an i64 from the wire as a zigzag varint.
567 */
568func (p *TCompactProtocol) ReadI64() (value int64, err TProtocolException) {
569 v, e := p.readVarint64()
570 if e != nil {
571 return 0, NewTProtocolExceptionFromOsError(e)
572 }
573 value = p.zigzagToInt64(v)
574 return value, nil
575}
576
577/**
578 * No magic here - just read a double off the wire.
579 */
580func (p *TCompactProtocol) ReadDouble() (value float64, err TProtocolException) {
581 longBits := make([]byte, 8)
582 _, e := p.trans.ReadAll(longBits)
583 if e != nil {
584 return 0.0, NewTProtocolExceptionFromOsError(e)
585 }
586 return math.Float64frombits(p.bytesToUint64(longBits)), nil
587}
588
589/**
590 * Reads a []byte (via readBinary), and then UTF-8 decodes it.
591 */
592func (p *TCompactProtocol) ReadString() (value string, err TProtocolException) {
593 v, e := p.ReadBinary()
594 return string(v), NewTProtocolExceptionFromOsError(e)
595}
596
597/**
598 * Read a []byte from the wire.
599 */
600func (p *TCompactProtocol) ReadBinary() (value []byte, err TProtocolException) {
601 length, e := p.readVarint32()
602 if e != nil {
603 return []byte{}, NewTProtocolExceptionFromOsError(e)
604 }
605 if length == 0 {
606 return []byte{}, nil
607 }
608
609 buf := make([]byte, length)
610 p.trans.ReadAll(buf)
611 return buf, nil
612}
613
614func (p *TCompactProtocol) Flush() (err TProtocolException) {
615 return NewTProtocolExceptionFromOsError(p.trans.Flush())
616}
617
618func (p *TCompactProtocol) Skip(fieldType TType) (err TProtocolException) {
619 return SkipDefaultDepth(p, fieldType)
620}
621
622func (p *TCompactProtocol) Transport() TTransport {
623 return p.trans
624}
625
626//
627// Internal writing methods
628//
629
630/**
631 * Abstract method for writing the start of lists and sets. List and sets on
632 * the wire differ only by the type indicator.
633 */
634func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, os.Error) {
635 if size <= 14 {
636 return p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
637 }
638 n, err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
639 if err != nil {
640 return n, err
641 }
642 m, err := p.writeVarint32(int32(size))
643 return n + m, err
644}
645
646/**
647 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
648 * TODO(pomack): make a permanent buffer like writeVarint64?
649 */
650func (p *TCompactProtocol) writeVarint32(n int32) (int, os.Error) {
651 i32buf := make([]byte, 5)
652 idx := 0
653 for {
654 if (n & ^0x7F) == 0 {
655 i32buf[idx] = byte(n)
656 idx++
657 // p.writeByteDirect(byte(n));
658 break
659 // return;
660 } else {
661 i32buf[idx] = byte((n & 0x7F) | 0x80)
662 idx++
663 // p.writeByteDirect(byte(((n & 0x7F) | 0x80)));
664 u := uint32(n)
665 n = int32(u >> 7)
666 }
667 }
668 return p.trans.Write(i32buf[0:idx])
669}
670
671/**
672 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
673 */
674func (p *TCompactProtocol) writeVarint64(n int64) (int, os.Error) {
675 varint64out := make([]byte, 10)
676 idx := 0
677 for {
678 if (n & ^0x7F) == 0 {
679 varint64out[idx] = byte(n)
680 idx++
681 break
682 } else {
683 varint64out[idx] = byte((n & 0x7F) | 0x80)
684 idx++
685 u := uint64(n)
686 n = int64(u >> 7)
687 }
688 }
689 return p.trans.Write(varint64out[0:idx])
690}
691
692/**
693 * Convert l into a zigzag long. This allows negative numbers to be
694 * represented compactly as a varint.
695 */
696func (p *TCompactProtocol) int64ToZigzag(l int64) int64 {
697 return (l << 1) ^ (l >> 63)
698}
699
700/**
701 * Convert l into a zigzag long. This allows negative numbers to be
702 * represented compactly as a varint.
703 */
704func (p *TCompactProtocol) int32ToZigzag(n int32) int32 {
705 return (n << 1) ^ (n >> 31)
706}
707
708func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) {
709 binary.LittleEndian.PutUint64(buf, n)
710}
711
712func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) {
713 binary.LittleEndian.PutUint64(buf, uint64(n))
714}
715
716/**
717 * Writes a byte without any possiblity of all that field header nonsense.
718 * Used internally by other writing methods that know they need to write a byte.
719 */
720func (p *TCompactProtocol) writeByteDirect(b byte) (int, os.Error) {
721 return p.trans.Write([]byte{b})
722}
723
724/**
725 * Writes a byte without any possiblity of all that field header nonsense.
726 */
727func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, os.Error) {
728 return p.writeByteDirect(byte(n))
729}
730
731
732//
733// Internal reading methods
734//
735
736/**
737 * Read an i32 from the wire as a varint. The MSB of each byte is set
738 * if there is another byte to follow. This can read up to 5 bytes.
739 */
740func (p *TCompactProtocol) readVarint32() (int32, os.Error) {
741 // if the wire contains the right stuff, this will just truncate the i64 we
742 // read and get us the right sign.
743 v, err := p.readVarint64()
744 return int32(v), err
745}
746
747
748/**
749 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
750 * if there is another byte to follow. This can read up to 10 bytes.
751 */
752func (p *TCompactProtocol) readVarint64() (int64, os.Error) {
753 shift := uint(0)
754 result := int64(0)
755 for {
756 b, err := p.ReadByte()
757 if err != nil {
758 return 0, err
759 }
760 result |= int64(b&0x7f) << shift
761 if (b & 0x80) != 0x80 {
762 break
763 }
764 shift += 7
765 }
766 return result, nil
767}
768
769
770//
771// encoding helpers
772//
773
774/**
775 * Convert from zigzag int to int.
776 */
777func (p *TCompactProtocol) zigzagToInt32(n int32) int32 {
778 u := uint32(n)
779 return int32(u>>1) ^ -(n & 1)
780}
781
782/**
783 * Convert from zigzag long to long.
784 */
785func (p *TCompactProtocol) zigzagToInt64(n int64) int64 {
786 u := uint64(n)
787 return int64(u>>1) ^ -(n & 1)
788}
789
790/**
791 * Note that it's important that the mask bytes are long literals,
792 * otherwise they'll default to ints, and when you shift an int left 56 bits,
793 * you just get a messed up int.
794 */
795func (p *TCompactProtocol) bytesToInt64(b []byte) int64 {
796 return int64(binary.LittleEndian.Uint64(b))
797}
798
799/**
800 * Note that it's important that the mask bytes are long literals,
801 * otherwise they'll default to ints, and when you shift an int left 56 bits,
802 * you just get a messed up int.
803 */
804func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 {
805 return binary.LittleEndian.Uint64(b)
806}
807
808//
809// type testing and converting
810//
811
812func (p *TCompactProtocol) isBoolType(b byte) bool {
813 return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE
814}
815
816/**
817 * Given a TCompactType constant, convert it to its corresponding
818 * TType value.
819 */
820func (p *TCompactProtocol) getTType(t TCompactType) (TType, os.Error) {
821 switch byte(t) & 0x0f {
822 case STOP:
823 return STOP, nil
824 case COMPACT_BOOLEAN_FALSE:
825 case COMPACT_BOOLEAN_TRUE:
826 return BOOL, nil
827 case COMPACT_BYTE:
828 return BYTE, nil
829 case COMPACT_I16:
830 return I16, nil
831 case COMPACT_I32:
832 return I32, nil
833 case COMPACT_I64:
834 return I64, nil
835 case COMPACT_DOUBLE:
836 return DOUBLE, nil
837 case COMPACT_BINARY:
838 return STRING, nil
839 case COMPACT_LIST:
840 return LIST, nil
841 case COMPACT_SET:
842 return SET, nil
843 case COMPACT_MAP:
844 return MAP, nil
845 case COMPACT_STRUCT:
846 return STRUCT, nil
847 }
848 return STOP, NewTException("don't know what type: " + string(t&0x0f))
849}
850
851/**
852 * Given a TType value, find the appropriate TCompactProtocol.Types constant.
853 */
854func (p *TCompactProtocol) getCompactType(t TType) TCompactType {
855 return _TTypeToCompactType[int(t)]
856}