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