github.com/artyom/thrift@v0.0.0-20130902103359-388840a05deb/compact_protocol.go (about)

     1  /*
     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  
    20  package thrift
    21  
    22  import (
    23  	"encoding/binary"
    24  	"fmt"
    25  	"io"
    26  	"math"
    27  	"strings"
    28  )
    29  
    30  const (
    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  
    38  type tCompactType byte
    39  
    40  const (
    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  
    55  var (
    56  	ttypeToCompactType map[TType]tCompactType
    57  )
    58  
    59  func 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  
    76  type TCompactProtocolFactory struct{}
    77  
    78  func NewTCompactProtocolFactory() *TCompactProtocolFactory {
    79  	return &TCompactProtocolFactory{}
    80  }
    81  
    82  func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol {
    83  	return NewTCompactProtocol(trans)
    84  }
    85  
    86  type 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
   105  func 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.
   115  func (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  
   133  func (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.
   138  func (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.
   147  func (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  
   153  func (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.
   166  func (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  
   203  func (p *TCompactProtocol) WriteFieldEnd() error { return nil }
   204  
   205  func (p *TCompactProtocol) WriteFieldStop() error {
   206  	_, err := p.writeByteDirect(STOP)
   207  	return NewTProtocolException(err)
   208  }
   209  
   210  func (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  
   223  func (p *TCompactProtocol) WriteMapEnd() error { return nil }
   224  
   225  // Write a list header.
   226  func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) error {
   227  	_, err := p.writeCollectionBegin(elemType, size)
   228  	return NewTProtocolException(err)
   229  }
   230  
   231  func (p *TCompactProtocol) WriteListEnd() error { return nil }
   232  
   233  // Write a set header.
   234  func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) error {
   235  	_, err := p.writeCollectionBegin(elemType, size)
   236  	return NewTProtocolException(err)
   237  }
   238  
   239  func (p *TCompactProtocol) WriteSetEnd() error { return nil }
   240  
   241  func (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!
   258  func (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.
   264  func (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.
   270  func (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.
   276  func (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.
   282  func (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.
   290  func (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.
   297  func (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.
   314  func (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  
   340  func (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.
   344  func (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.
   352  func (p *TCompactProtocol) ReadStructEnd() error {
   353  	// consume the last field we read off the wire.
   354  	p.lastFieldId = p.lastField[len(p.lastField)-1]
   355  	return nil
   356  }
   357  
   358  // Read a field header off the wire.
   359  func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) {
   360  	t, err := p.ReadByte()
   361  	if err != nil {
   362  		return
   363  	}
   364  
   365  	// if it's a stop, then we can return immediately, as the struct is over.
   366  	if (t & 0x0f) == STOP {
   367  		return "", STOP, 0,nil
   368  	}
   369  
   370  	// mask off the 4 MSB of the type header. it could contain a field id delta.
   371  	modifier := int16((t & 0xf0) >> 4)
   372  	if modifier == 0 {
   373  		// not a delta. look ahead for the zigzag varint field id.
   374  		id, err = p.ReadI16()
   375  		if err != nil {
   376  			return
   377  		}
   378  	} else {
   379  		// has a delta. add the delta to the last read field id.
   380  		id = int16(p.lastFieldId) + modifier
   381  	}
   382  	typeId, e := p.getTType(tCompactType(t & 0x0f))
   383  	if e != nil {
   384  		err = NewTProtocolException(e)
   385  		return
   386  	}
   387  
   388  	// if this happens to be a boolean field, the value is encoded in the type
   389  	if p.isBoolType(t) {
   390  		// save the boolean value in a special instance variable.
   391  		p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE)
   392  		p.boolValueIsNotNull = true
   393  	}
   394  
   395  	// push the new field onto the field stack so we can keep the deltas going.
   396  	p.lastFieldId = int(id)
   397  	return
   398  }
   399  
   400  func (p *TCompactProtocol) ReadFieldEnd() error { return nil }
   401  
   402  // Read a map header off the wire. If the size is zero, skip reading the key
   403  // and value type. This means that 0-length maps will yield TMaps without the
   404  // "correct" types.
   405  func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) {
   406  	size32, e := p.readVarint32()
   407  	size = int(size32)
   408  	if e != nil {
   409  		err = NewTProtocolException(e)
   410  		return
   411  	}
   412  	keyAndValueType := byte(STOP)
   413  	if size != 0 {
   414  		keyAndValueType, err = p.ReadByte()
   415  		if err != nil {
   416  			return
   417  		}
   418  	}
   419  	keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4))
   420  	valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf))
   421  	return
   422  }
   423  
   424  func (p *TCompactProtocol) ReadMapEnd() error { return nil }
   425  
   426  // Read a list header off the wire. If the list size is 0-14, the size will
   427  // be packed into the element type header. If it's a longer list, the 4 MSB
   428  // of the element type header will be 0xF, and a varint will follow with the
   429  // true size.
   430  func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err error) {
   431  	size_and_type, err := p.ReadByte()
   432  	if err != nil {
   433  		return
   434  	}
   435  	size = int((size_and_type >> 4) & 0x0f)
   436  	if size == 15 {
   437  		size2, e := p.readVarint32()
   438  		if e != nil {
   439  			err = NewTProtocolException(e)
   440  			return
   441  		}
   442  		size = int(size2)
   443  	}
   444  	elemType, e := p.getTType(tCompactType(size_and_type))
   445  	if e != nil {
   446  		err = NewTProtocolException(e)
   447  		return
   448  	}
   449  	return
   450  }
   451  
   452  func (p *TCompactProtocol) ReadListEnd() error { return nil }
   453  
   454  // Read a set header off the wire. If the set size is 0-14, the size will
   455  // be packed into the element type header. If it's a longer set, the 4 MSB
   456  // of the element type header will be 0xF, and a varint will follow with the
   457  // true size.
   458  func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err error) {
   459  	return p.ReadListBegin()
   460  }
   461  
   462  func (p *TCompactProtocol) ReadSetEnd() error { return nil }
   463  
   464  // Read a boolean off the wire. If this is a boolean field, the value should
   465  // already have been read during readFieldBegin, so we'll just consume the
   466  // pre-stored value. Otherwise, read a byte.
   467  func (p *TCompactProtocol) ReadBool() (value bool, err error) {
   468  	if p.boolValueIsNotNull {
   469  		p.boolValueIsNotNull = false
   470  		return p.boolValue, nil
   471  	}
   472  	v, err := p.ReadByte()
   473  	return v == COMPACT_BOOLEAN_TRUE, err
   474  }
   475  
   476  // Read a single byte off the wire. Nothing interesting here.
   477  func (p *TCompactProtocol) ReadByte() (value byte, err error) {
   478  	buf := []byte{0}
   479  	_, e := io.ReadFull(p.trans, buf)
   480  	if e != nil {
   481  		return 0, NewTProtocolException(e)
   482  	}
   483  	return buf[0], nil
   484  }
   485  
   486  // Read an i16 from the wire as a zigzag varint.
   487  func (p *TCompactProtocol) ReadI16() (value int16, err error) {
   488  	v, err := p.ReadI32()
   489  	return int16(v), err
   490  }
   491  
   492  // Read an i32 from the wire as a zigzag varint.
   493  func (p *TCompactProtocol) ReadI32() (value int32, err error) {
   494  	v, e := p.readVarint32()
   495  	if e != nil {
   496  		return 0, NewTProtocolException(e)
   497  	}
   498  	value = p.zigzagToInt32(v)
   499  	return value, nil
   500  }
   501  
   502  // Read an i64 from the wire as a zigzag varint.
   503  func (p *TCompactProtocol) ReadI64() (value int64, err error) {
   504  	v, e := p.readVarint64()
   505  	if e != nil {
   506  		return 0, NewTProtocolException(e)
   507  	}
   508  	value = p.zigzagToInt64(v)
   509  	return value, nil
   510  }
   511  
   512  // No magic here - just read a double off the wire.
   513  func (p *TCompactProtocol) ReadDouble() (value float64, err error) {
   514  	longBits := make([]byte, 8)
   515  	_, e := io.ReadFull(p.trans, longBits)
   516  	if e != nil {
   517  		return 0.0, NewTProtocolException(e)
   518  	}
   519  	return math.Float64frombits(p.bytesToUint64(longBits)), nil
   520  }
   521  
   522  // Reads a []byte (via readBinary), and then UTF-8 decodes it.
   523  func (p *TCompactProtocol) ReadString() (value string, err error) {
   524  	v, e := p.ReadBinary()
   525  	return string(v), NewTProtocolException(e)
   526  }
   527  
   528  // Read a []byte from the wire.
   529  func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
   530  	length, e := p.readVarint32()
   531  	if e != nil {
   532  		return []byte{}, NewTProtocolException(e)
   533  	}
   534  	if length == 0 {
   535  		return []byte{}, nil
   536  	}
   537  
   538  	buf := make([]byte, length)
   539  	_, e = io.ReadFull(p.trans, buf)
   540  	return buf, NewTProtocolException(e)
   541  }
   542  
   543  func (p *TCompactProtocol) Flush() (err error) {
   544  	return NewTProtocolException(p.trans.Flush())
   545  }
   546  
   547  func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
   548  	return SkipDefaultDepth(p, fieldType)
   549  }
   550  
   551  func (p *TCompactProtocol) Transport() TTransport {
   552  	return p.trans
   553  }
   554  
   555  //
   556  // Internal writing methods
   557  //
   558  
   559  // Abstract method for writing the start of lists and sets. List and sets on
   560  // the wire differ only by the type indicator.
   561  func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) {
   562  	if size <= 14 {
   563  		return p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
   564  	}
   565  	n, err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
   566  	if err != nil {
   567  		return n, err
   568  	}
   569  	m, err := p.writeVarint32(int32(size))
   570  	return n + m, err
   571  }
   572  
   573  // Write an i32 as a varint. Results in 1-5 bytes on the wire.
   574  // TODO(pomack): make a permanent buffer like writeVarint64?
   575  func (p *TCompactProtocol) writeVarint32(n int32) (int, error) {
   576  	i32buf := make([]byte, 5)
   577  	idx := 0
   578  	for {
   579  		if (n & ^0x7F) == 0 {
   580  			i32buf[idx] = byte(n)
   581  			idx++
   582  			// p.writeByteDirect(byte(n));
   583  			break
   584  			// return;
   585  		} else {
   586  			i32buf[idx] = byte((n & 0x7F) | 0x80)
   587  			idx++
   588  			// p.writeByteDirect(byte(((n & 0x7F) | 0x80)));
   589  			u := uint32(n)
   590  			n = int32(u >> 7)
   591  		}
   592  	}
   593  	return p.trans.Write(i32buf[0:idx])
   594  }
   595  
   596  // Write an i64 as a varint. Results in 1-10 bytes on the wire.
   597  func (p *TCompactProtocol) writeVarint64(n int64) (int, error) {
   598  	varint64out := make([]byte, 10)
   599  	idx := 0
   600  	for {
   601  		if (n & ^0x7F) == 0 {
   602  			varint64out[idx] = byte(n)
   603  			idx++
   604  			break
   605  		} else {
   606  			varint64out[idx] = byte((n & 0x7F) | 0x80)
   607  			idx++
   608  			u := uint64(n)
   609  			n = int64(u >> 7)
   610  		}
   611  	}
   612  	return p.trans.Write(varint64out[0:idx])
   613  }
   614  
   615  // Convert l into a zigzag long. This allows negative numbers to be
   616  // represented compactly as a varint.
   617  func (p *TCompactProtocol) int64ToZigzag(l int64) int64 {
   618  	return (l << 1) ^ (l >> 63)
   619  }
   620  
   621  // Convert l into a zigzag long. This allows negative numbers to be
   622  // represented compactly as a varint.
   623  func (p *TCompactProtocol) int32ToZigzag(n int32) int32 {
   624  	return (n << 1) ^ (n >> 31)
   625  }
   626  
   627  func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) {
   628  	binary.LittleEndian.PutUint64(buf, n)
   629  }
   630  
   631  func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) {
   632  	binary.LittleEndian.PutUint64(buf, uint64(n))
   633  }
   634  
   635  // Writes a byte without any possiblity of all that field header nonsense.
   636  // Used internally by other writing methods that know they need to write a byte.
   637  func (p *TCompactProtocol) writeByteDirect(b byte) (int, error) {
   638  	return p.trans.Write([]byte{b})
   639  }
   640  
   641  // Writes a byte without any possiblity of all that field header nonsense.
   642  func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, error) {
   643  	return p.writeByteDirect(byte(n))
   644  }
   645  
   646  //
   647  // Internal reading methods
   648  //
   649  
   650  // Read an i32 from the wire as a varint. The MSB of each byte is set
   651  // if there is another byte to follow. This can read up to 5 bytes.
   652  func (p *TCompactProtocol) readVarint32() (int32, error) {
   653  	// if the wire contains the right stuff, this will just truncate the i64 we
   654  	// read and get us the right sign.
   655  	v, err := p.readVarint64()
   656  	return int32(v), err
   657  }
   658  
   659  // Read an i64 from the wire as a proper varint. The MSB of each byte is set
   660  // if there is another byte to follow. This can read up to 10 bytes.
   661  func (p *TCompactProtocol) readVarint64() (int64, error) {
   662  	shift := uint(0)
   663  	result := int64(0)
   664  	for {
   665  		b, err := p.ReadByte()
   666  		if err != nil {
   667  			return 0, err
   668  		}
   669  		result |= int64(b&0x7f) << shift
   670  		if (b & 0x80) != 0x80 {
   671  			break
   672  		}
   673  		shift += 7
   674  	}
   675  	return result, nil
   676  }
   677  
   678  //
   679  // encoding helpers
   680  //
   681  
   682  // Convert from zigzag int to int.
   683  func (p *TCompactProtocol) zigzagToInt32(n int32) int32 {
   684  	u := uint32(n)
   685  	return int32(u>>1) ^ -(n & 1)
   686  }
   687  
   688  // Convert from zigzag long to long.
   689  func (p *TCompactProtocol) zigzagToInt64(n int64) int64 {
   690  	u := uint64(n)
   691  	return int64(u>>1) ^ -(n & 1)
   692  }
   693  
   694  // Note that it's important that the mask bytes are long literals,
   695  // otherwise they'll default to ints, and when you shift an int left 56 bits,
   696  // you just get a messed up int.
   697  func (p *TCompactProtocol) bytesToInt64(b []byte) int64 {
   698  	return int64(binary.LittleEndian.Uint64(b))
   699  }
   700  
   701  // Note that it's important that the mask bytes are long literals,
   702  // otherwise they'll default to ints, and when you shift an int left 56 bits,
   703  // you just get a messed up int.
   704  func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 {
   705  	return binary.LittleEndian.Uint64(b)
   706  }
   707  
   708  //
   709  // type testing and converting
   710  //
   711  
   712  func (p *TCompactProtocol) isBoolType(b byte) bool {
   713  	return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE
   714  }
   715  
   716  // Given a tCompactType constant, convert it to its corresponding
   717  // TType value.
   718  func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) {
   719  	switch byte(t) & 0x0f {
   720  	case STOP:
   721  		return STOP, nil
   722  	case COMPACT_BOOLEAN_FALSE:
   723  	case COMPACT_BOOLEAN_TRUE:
   724  		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.
   750  func (p *TCompactProtocol) getCompactType(t TType) tCompactType {
   751  	return ttypeToCompactType[t]
   752  }