You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2015/03/05 23:43:49 UTC

thrift git commit: THRIFT-3022 Compact protocol for Haxe Client: Haxe Patch: Jens Geyer

Repository: thrift
Updated Branches:
  refs/heads/master 6f7399b35 -> 426ab8680


THRIFT-3022 Compact protocol for Haxe
Client: Haxe
Patch: Jens Geyer

This closes #388


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/426ab868
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/426ab868
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/426ab868

Branch: refs/heads/master
Commit: 426ab8680126ac914c566adbcda3d6e93d57df64
Parents: 6f7399b
Author: Jens Geyer <je...@apache.org>
Authored: Mon Mar 2 23:37:15 2015 +0100
Committer: Jens Geyer <je...@apache.org>
Committed: Thu Mar 5 23:43:23 2015 +0100

----------------------------------------------------------------------
 .../org/apache/thrift/helper/BitConverter.hx    | 159 ++++
 lib/haxe/src/org/apache/thrift/helper/ZigZag.hx | 128 ++++
 .../apache/thrift/protocol/TCompactProtocol.hx  | 730 +++++++++++++++++++
 .../thrift/protocol/TCompactProtocolFactory.hx  |  40 +
 test/haxe/src/Arguments.hx                      |   3 +-
 test/haxe/src/TestClient.hx                     | 150 ++--
 test/haxe/src/TestMacro.hx                      |   8 +-
 test/haxe/src/TestServer.hx                     |   5 +-
 test/haxe/src/TestServerHandler.hx              |  12 +-
 9 files changed, 1162 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
----------------------------------------------------------------------
diff --git a/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
new file mode 100644
index 0000000..7f7c8f7
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+
+class BitConverter {
+
+    public static function DoubleToInt64Bits( db : Float) : Int64 {
+        var buf = new BytesBuffer();
+        buf.addDouble( db);
+        return bytesToLong( buf.getBytes());
+    }
+
+
+    public static function Int64BitsToDouble( i64 : Int64) : Float {
+        var buf = new BytesBuffer();
+        buf.add( fixedLongToBytes( i64));
+        return buf.getBytes().getDouble(0);
+    }
+
+
+
+    /**
+     * Convert a long into little-endian bytes in buf starting at off and going
+     * until off+7.
+     */
+    public static function fixedLongToBytes( n : Int64)  : Bytes {
+        var buf = Bytes.alloc(8);
+        buf.set( 0, Int64.getLow( Int64.and( n, Int64.make(0, 0xff))));
+        buf.set( 1, Int64.getLow( Int64.and( Int64.shr( n, 8),  Int64.make(0, 0xff))));
+        buf.set( 2, Int64.getLow( Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff))));
+        buf.set( 3, Int64.getLow( Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff))));
+        buf.set( 4, Int64.getLow( Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff))));
+        buf.set( 5, Int64.getLow( Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff))));
+        buf.set( 6, Int64.getLow( Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff))));
+        buf.set( 7, Int64.getLow( Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff))));
+        return buf;
+    }
+
+    /**
+     * Note that it's important that the mask bytes are long literals,
+     * otherwise they'll default to ints, and when you shift an int left 56 bits,
+     * you just get a messed up int.
+     */
+    public static function bytesToLong( bytes : Bytes) : Int64 {
+        var result : Int64 = Int64.make(0, 0);
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(7)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(6)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(5)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(4)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(3)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(2)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(1)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(0)));
+        return result;
+    }
+
+
+    #if debug
+    private static function TestBTL( test : Int64) : Void {
+        var buf : Bytes = fixedLongToBytes( test);
+        var erg = bytesToLong(buf);
+        if ( Int64.compare( erg, test) != 0)
+            throw 'BitConverter.bytesToLongTest($test) failed: $erg';
+    }
+    #end
+
+
+    #if debug
+    private static function TestPair( a : Float, b : Int64) : Void {
+        var bx = DoubleToInt64Bits(a);
+        if ( Int64.compare( bx, b) != 0)
+            throw 'BitConverter.TestPair: DoubleToInt64Bits($a): expected $b, got $bx';
+        var ax = Int64BitsToDouble(b);
+        if( ax != a)
+            throw 'BitConverter.TestPair: Int64BitsToDouble($b: expected $a, got  $ax';
+    }
+    #end
+
+
+    #if debug
+    public static function UnitTest() : Void {
+
+        // bytesToLong()
+        var i : Int;
+        TestBTL( Int64.make(0,0));
+        for ( i in 0 ... 62) {
+            TestBTL( Int64.shl( Int64.make(0,1), i));
+            TestBTL( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+        }
+        TestBTL( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+        TestBTL( Int64.make(cast(0x80000000,Int),0x00000000));
+
+        // DoubleToInt64Bits;
+        TestPair( 1.0000000000000000E+000,  Int64.make(cast(0x3FF00000,Int),cast(0x00000000,Int)));
+        TestPair( 1.5000000000000000E+001,  Int64.make(cast(0x402E0000,Int),cast(0x00000000,Int)));
+        TestPair( 2.5500000000000000E+002,  Int64.make(cast(0x406FE000,Int),cast(0x00000000,Int)));
+        TestPair( 4.2949672950000000E+009,  Int64.make(cast(0x41EFFFFF,Int),cast(0xFFE00000,Int)));
+        TestPair( 3.9062500000000000E-003,  Int64.make(cast(0x3F700000,Int),cast(0x00000000,Int)));
+        TestPair( 2.3283064365386963E-010,  Int64.make(cast(0x3DF00000,Int),cast(0x00000000,Int)));
+        TestPair( 1.2345678901230000E-300,  Int64.make(cast(0x01AA74FE,Int),cast(0x1C1E7E45,Int)));
+        TestPair( 1.2345678901234500E-150,  Int64.make(cast(0x20D02A36,Int),cast(0x586DB4BB,Int)));
+        TestPair( 1.2345678901234565E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FA,Int)));
+        TestPair( 1.2345678901234567E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FB,Int)));
+        TestPair( 1.2345678901234569E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FC,Int)));
+        TestPair( 1.2345678901234569E+150,  Int64.make(cast(0x5F182344,Int),cast(0xCD3CDF9F,Int)));
+        TestPair( 1.2345678901234569E+300,  Int64.make(cast(0x7E3D7EE8,Int),cast(0xBCBBD352,Int)));
+        TestPair( -1.7976931348623157E+308, Int64.make(cast(0xFFEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( 1.7976931348623157E+308,  Int64.make(cast(0x7FEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( 4.9406564584124654E-324,  Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+        TestPair( 0.0000000000000000E+000,  Int64.make(cast(0x00000000,Int),cast(0x00000000,Int)));
+        TestPair( 4.94065645841247E-324,    Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+        TestPair( 3.2378592100206092E-319,  Int64.make(cast(0x00000000,Int),cast(0x0000FFFF,Int)));
+        TestPair( 1.3906711615669959E-309,  Int64.make(cast(0x0000FFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( Math.NEGATIVE_INFINITY,   Int64.make(cast(0xFFF00000,Int),cast(0x00000000,Int)));
+        TestPair( Math.POSITIVE_INFINITY,   Int64.make(cast(0x7FF00000,Int),cast(0x00000000,Int)));
+
+        // NaN is special
+        var i64nan = DoubleToInt64Bits( Math.NaN);
+        var i64cmp = Int64.make(cast(0xFFF80000, Int), cast(0x00000000, Int));
+        if ( ! Math.isNaN( Int64BitsToDouble( i64cmp)))
+            throw 'BitConverter NaN-Test #1: expected NaN';
+
+        // For doubles, a quiet NaN is a bit pattern
+        // between 7FF8000000000000 and 7FFFFFFFFFFFFFFF
+        //      or FFF8000000000000 and FFFFFFFFFFFFFFFF
+        var min1 = Int64.make( cast(0x7FF80000, Int), cast(0x00000000, Int));
+        var max1 = Int64.make( cast(0x7FFFFFFF, Int), cast(0xFFFFFFFF, Int));
+        var min2 = Int64.make( cast(0xFFF80000, Int), cast(0x00000000, Int));
+        var max2 = Int64.make( cast(0xFFFFFFFF, Int), cast(0xFFFFFFFF, Int));
+        var ok1 =  (Int64.compare( min1, i64nan) <= 0) && (Int64.compare( i64nan, max1) <= 0);
+        var ok2 =  (Int64.compare( min2, i64nan) <= 0) && (Int64.compare( i64nan, max2) <= 0);
+        if( ! (ok1 || ok2))
+            throw 'BitConverter NaN-Test #2: failed';
+    }
+    #end
+
+}
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
----------------------------------------------------------------------
diff --git a/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
new file mode 100644
index 0000000..862060d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import haxe.Int64;
+
+class ZigZag {
+
+    /**
+     * Convert n into a zigzag int. This allows negative numbers to be
+     * represented compactly as a varint.
+     */
+    public static function FromInt( n : Int) : UInt    {
+        return cast(n << 1,UInt) ^ cast(n >> 31,UInt);
+    }
+
+
+    /**
+     * Convert from zigzag int to int.
+     */
+    public static function ToInt( n : UInt) : Int {
+        return (0x7FFFFFFF & cast(n >> 1,Int)) ^ (-cast(n & 1,Int));
+    }
+
+
+    /**
+     * Convert l into a zigzag long. This allows negative numbers to be
+     * represented compactly as a varint.
+     */
+    public static function FromLong( n : Int64) : Int64 {
+        return Int64.xor( Int64.shl(n, 1), Int64.shr(n, 63));
+    }
+
+
+    /**
+     * Convert from zigzag long to long.
+     */
+    public static function ToLong( n : Int64) : Int64 {
+        return Int64.xor(
+            Int64.and(
+                Int64.shr(n, 1),
+                Int64.make(0x7FFFFFFF, 0xFFFFFFFF)),
+            Int64.sub(
+                Int64.make(0, 0),
+                Int64.and(n, Int64.make(0,1))));
+    }
+
+
+    #if debug
+    private static function Test32( test : Int) : Void {
+        var a : UInt = ZigZag.FromInt( test);
+        var b : Int = ZigZag.ToInt(a);
+        if( test != b)
+            throw 'ZigZag.Test32($test) failed: a = $a, b = $b';
+    }
+    #end
+
+
+
+    #if debug
+    private static function Test64( test : haxe.Int64) : Void {
+        var a : Int64 = ZigZag.FromLong( test);
+        var b : Int64 = ZigZag.ToLong(a);
+        if( Int64.compare( test, b) != 0)
+            throw 'ZigZag.Test64($test) failed: a = $a, b = $b';
+    }
+    #end
+
+
+    #if debug
+    public static function UnitTest() : Void {
+      var u1 : UInt = 0xFFFFFFFE;
+      var u2 : UInt = 0xFFFFFFFF;
+
+      // protobuf testcases
+      if( FromInt(0)  != 0) throw 'pb #1 to ZigZag';
+      if( FromInt(-1) != 1) throw 'pb #2 to ZigZag';
+      if( FromInt(1)  != 2) throw 'pb #3 to ZigZag';
+      if( FromInt(-2) != 3) throw 'pb #4 to ZigZag';
+      if( FromInt(2147483647) != u1) throw 'pb #5 to ZigZag';
+      if( FromInt(-2147483648) != u2) throw 'pb #6 to ZigZag';
+
+      // protobuf testcases
+      if( ToInt(0) != 0) throw 'pb #1 from ZigZag';
+      if( ToInt(1) != -1) throw 'pb #2 from ZigZag';
+      if( ToInt(2) != 1) throw 'pb #3 from ZigZag';
+      if( ToInt(3) != -2) throw 'pb #4 from ZigZag';
+      if( ToInt(u1) != 2147483647) throw 'pb #5 from ZigZag, got ${ToInt(u1)}';
+      if( ToInt(u2) != -2147483648) throw 'pb #6 from ZigZag, got ${ToInt(u2)}';
+
+      // back and forth 32
+      Test32( 0);
+      for( i in 0 ... 30) {
+        Test32( 1 << i);
+        Test32( -(1  << i));
+      }
+      Test32( 0x7FFFFFFF);
+      Test32( cast(0x80000000,Int));
+
+      // back and forth 64
+      Test64( Int64.make(0,0));
+      for( i in 0 ... 62) {
+        Test64( Int64.shl( Int64.make(0,1), i));
+        Test64( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+      }
+      Test64( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+      Test64( Int64.make(cast(0x80000000,Int),0x00000000));
+    }
+    #end
+}
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
----------------------------------------------------------------------
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
new file mode 100644
index 0000000..d08a6d0
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
@@ -0,0 +1,730 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.ds.GenericStack;
+import haxe.Int32;
+import haxe.Int64;
+import haxe.Utf8;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.helper.ZigZag;
+import org.apache.thrift.helper.BitConverter;
+
+
+/**
+ * All of the on-wire type codes.
+ */
+class TCompactTypes {
+    public static inline var STOP          = 0x00;
+    public static inline var BOOLEAN_TRUE  = 0x01;
+    public static inline var BOOLEAN_FALSE = 0x02;
+    public static inline var BYTE          = 0x03;
+    public static inline var I16           = 0x04;
+    public static inline var I32           = 0x05;
+    public static inline var I64           = 0x06;
+    public static inline var DOUBLE        = 0x07;
+    public static inline var BINARY        = 0x08;
+    public static inline var LIST          = 0x09;
+    public static inline var SET           = 0x0A;
+    public static inline var MAP           = 0x0B;
+    public static inline var STRUCT        = 0x0C;
+}
+
+/**
+* Binary protocol implementation for thrift.
+*/
+class TCompactProtocol implements TProtocol {
+
+    private static var ANONYMOUS_STRUCT : TStruct = new TStruct("");
+    private static var TSTOP : TField = new TField("", TType.STOP, 0);
+
+    private static inline var PROTOCOL_ID : Int = 0x82;
+    private static inline var VERSION : Int = 1;
+    private static inline var VERSION_MASK : Int = 0x1f; // 0001 1111
+    private static inline var TYPE_MASK : Int = 0xE0; // 1110 0000
+    private static inline var TYPE_BITS : Int = 0x07; // 0000 0111
+    private static inline var TYPE_SHIFT_AMOUNT : Int = 5;
+
+
+    private static var ttypeToCompactType = [
+        TType.STOP    => TCompactTypes.STOP,
+        TType.BOOL    => TCompactTypes.BOOLEAN_TRUE,
+        TType.BYTE    => TCompactTypes.BYTE,
+        TType.DOUBLE  => TCompactTypes.DOUBLE,
+        TType.I16     => TCompactTypes.I16,
+        TType.I32     => TCompactTypes.I32,
+        TType.I64     => TCompactTypes.I64,
+        TType.STRING  => TCompactTypes.BINARY,
+        TType.STRUCT  => TCompactTypes.STRUCT,
+        TType.MAP     => TCompactTypes.MAP,
+        TType.SET     => TCompactTypes.SET,
+        TType.LIST    => TCompactTypes.LIST
+    ];
+
+    private static var tcompactTypeToType = [
+        TCompactTypes.STOP          => TType.STOP,
+        TCompactTypes.BOOLEAN_TRUE  => TType.BOOL,
+        TCompactTypes.BOOLEAN_FALSE => TType.BOOL,
+        TCompactTypes.BYTE          => TType.BYTE,
+        TCompactTypes.I16           => TType.I16,
+        TCompactTypes.I32           => TType.I32,
+        TCompactTypes.I64           => TType.I64,
+        TCompactTypes.DOUBLE        => TType.DOUBLE,
+        TCompactTypes.BINARY        => TType.STRING,
+        TCompactTypes.LIST          => TType.LIST,
+        TCompactTypes.SET           => TType.SET,
+        TCompactTypes.MAP           => TType.MAP,
+        TCompactTypes.STRUCT        => TType.STRUCT
+    ];
+
+
+    /**
+     * Used to keep track of the last field for the current and previous structs,
+     * so we can do the delta stuff.
+     */
+    private var lastField_ : GenericStack<Int> = new GenericStack<Int>();
+    private var lastFieldId_ : Int = 0;
+
+    /**
+     * If we encounter a boolean field begin, save the TField here so it can
+     * have the value incorporated.
+     */
+    private var booleanField_ : Null<TField>;
+
+    /**
+     * If we Read a field header, and it's a boolean field, save the boolean
+     * value here so that ReadBool can use it.
+     */
+    private var boolValue_ : Null<Bool>;
+
+
+    // whether the underlying system holds Strings as UTF-8
+    // http://old.haxe.org/manual/encoding
+    private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш");
+
+    // the transport used
+    public var trans(default,null) : TTransport;
+
+
+    // TCompactProtocol Constructor
+    public function new( trans : TTransport) {
+        this.trans = trans;
+    }
+
+    public function getTransport() : TTransport {
+      return trans;
+    }
+
+
+    public function Reset() : Void{
+        while ( ! lastField_.isEmpty()) {
+            lastField_.pop();
+        }
+        lastFieldId_ = 0;
+    }
+
+
+    /**
+     * Writes a byte without any possibility of all that field header nonsense.
+     * Used internally by other writing methods that know they need to Write a byte.
+     */
+    private function WriteByteDirect( b : Int) : Void {
+        var buf = Bytes.alloc(1);
+        buf.set( 0, b);
+        trans.write( buf, 0, 1);
+    }
+
+    /**
+     * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+     */
+    private function WriteVarint32( n : UInt) : Void {
+        var i32buf = new BytesBuffer();
+        while (true)
+        {
+            if ((n & ~0x7F) == 0)
+            {
+                i32buf.addByte( n & 0xFF);
+                break;
+            }
+            else
+            {
+                i32buf.addByte( (n & 0x7F) | 0x80);
+                n >>= 7;
+            }
+        }
+
+        var tmp = i32buf.getBytes();
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    /**
+    * Write a message header to the wire. Compact Protocol messages contain the
+    * protocol version so we can migrate forwards in the future if need be.
+    */
+    public function writeMessageBegin( message : TMessage) : Void {
+        Reset();
+
+        var versionAndType : Int =  (VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
+        WriteByteDirect( PROTOCOL_ID);
+        WriteByteDirect( versionAndType);
+        WriteVarint32( cast( message.seqid, UInt));
+        writeString( message.name);
+    }
+
+    /**
+     * Write a struct begin. This doesn't actually put anything on the wire. We
+     * use it as an opportunity to put special placeholder markers on the field
+     * stack so we can get the field id deltas correct.
+     */
+    public function writeStructBegin(struct:TStruct) : Void {
+        lastField_.add( lastFieldId_);
+        lastFieldId_ = 0;
+    }
+
+    /**
+     * Write a struct end. This doesn't actually put anything on the wire. We use
+     * this as an opportunity to pop the last field from the current struct off
+     * of the field stack.
+     */
+    public function writeStructEnd() : Void {
+        lastFieldId_ = lastField_.pop();
+    }
+
+    /**
+     * Write a field header containing the field id and field type. If the
+     * difference between the current field id and the last one is small (< 15),
+     * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+     * field id will follow the type header as a zigzag varint.
+     */
+    public function writeFieldBegin(field:TField) : Void {
+        if (field.type == TType.BOOL)
+            booleanField_ = field; // we want to possibly include the value, so we'll wait.
+        else
+            WriteFieldBeginInternal(field, 0xFF);
+    }
+
+    /**
+     * The workhorse of WriteFieldBegin. It has the option of doing a
+     * 'type override' of the type header. This is used specifically in the
+     * boolean field case.
+     */
+    private function WriteFieldBeginInternal( field : TField, typeOverride : Int) : Void {
+        // if there's a type override, use that.
+        var typeToWrite : Int;
+        if ( typeOverride == 0xFF)
+            typeToWrite = getCompactType( field.type);
+        else
+            typeToWrite = typeOverride;
+
+        // check if we can use delta encoding for the field id
+        if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15)
+        {
+            // Write them together
+            WriteByteDirect((field.id - lastFieldId_) << 4 | typeToWrite);
+        }
+        else
+        {
+            // Write them separate
+            WriteByteDirect(typeToWrite);
+            writeI16(field.id);
+        }
+
+        lastFieldId_ = field.id;
+    }
+
+    /**
+     * Write the STOP symbol so we know there are no more fields in this struct.
+     */
+    public function writeFieldStop() : Void {
+        WriteByteDirect( cast(TCompactTypes.STOP, Int));
+    }
+
+    /**
+     * Write a map header. If the map is empty, omit the key and value type
+     * headers, as we don't need any additional information to skip it.
+     */
+    public function writeMapBegin(map:TMap) : Void {
+        if (map.size == 0)
+        {
+            WriteByteDirect(0);
+        }
+        else
+        {
+            var kvtype = (getCompactType(map.keyType) << 4) | getCompactType(map.valueType);
+            WriteVarint32( cast( map.size, UInt));
+            WriteByteDirect( kvtype);
+        }
+    }
+
+    /**
+     * Write a list header.
+     */
+    public function writeListBegin( list : TList) : Void {
+        WriteCollectionBegin( list.elemType, list.size);
+    }
+
+    /**
+     * Write a set header.
+     */
+    public function writeSetBegin( set : TSet) : Void {
+        WriteCollectionBegin( set.elemType, set.size);
+    }
+
+    /**
+     * Write a boolean value. Potentially, this could be a boolean field, in
+     * which case the field header info isn't written yet. If so, decide what the
+     * right type header is for the value and then Write the field header.
+     * Otherwise, Write a single byte.
+     */
+    public function writeBool(b : Bool) : Void {
+        var bct : Int = b ? TCompactTypes.BOOLEAN_TRUE : TCompactTypes.BOOLEAN_FALSE;
+
+        if (booleanField_ != null)
+        {
+            // we haven't written the field header yet
+            WriteFieldBeginInternal( booleanField_, bct);
+            booleanField_ = null;
+        }
+        else
+        {
+            // we're not part of a field, so just Write the value.
+            WriteByteDirect( bct);
+        }
+    }
+
+    /**
+     * Write a byte. Nothing to see here!
+     */
+    public function writeByte( b : Int) : Void {
+        WriteByteDirect( b);
+    }
+
+    /**
+     * Write an I16 as a zigzag varint.
+     */
+    public function writeI16( i16 : Int) : Void {
+        WriteVarint32( ZigZag.FromInt( i16));
+    }
+
+    /**
+     * Write an i32 as a zigzag varint.
+     */
+    public function writeI32( i32 : Int) : Void {
+        WriteVarint32( ZigZag.FromInt( i32));
+    }
+
+    /**
+     * Write an i64 as a zigzag varint.
+     */
+    public function writeI64( i64 : haxe.Int64) : Void {
+        WriteVarint64(  ZigZag.FromLong( i64));
+    }
+
+    /**
+     * Write a double to the wire as 8 bytes.
+     */
+    public function writeDouble( dub : Float) : Void {
+        var data = BitConverter.fixedLongToBytes( BitConverter.DoubleToInt64Bits(dub));
+        trans.write( data, 0, data.length);
+    }
+
+    /**
+     * Write a string to the wire with a varint size preceding.
+     */
+    public function writeString(str : String) : Void {
+        var buf = new BytesBuffer();
+        if( utf8Strings)
+            buf.addString( str);  // no need to encode on UTF8 targets, the string is just fine
+        else
+            buf.addString( Utf8.encode( str));
+        var tmp = buf.getBytes();
+        writeBinary( tmp);
+    }
+
+    /**
+     * Write a byte array, using a varint for the size.
+     */
+    public function writeBinary( bin : Bytes) : Void {
+        WriteVarint32( cast(bin.length,UInt));
+        trans.write( bin, 0, bin.length);
+    }
+
+
+    // These methods are called by structs, but don't actually have any wire
+    // output or purpose.
+    public function writeMessageEnd() : Void { }
+    public function writeMapEnd() : Void { }
+    public function writeListEnd() : Void { }
+    public function writeSetEnd() : Void { }
+    public function writeFieldEnd() : Void { }
+
+    //
+    // Internal writing methods
+    //
+
+    /**
+     * Abstract method for writing the start of lists and sets. List and sets on
+     * the wire differ only by the type indicator.
+     */
+    private function WriteCollectionBegin( elemType : Int, size : Int) : Void {
+        if (size <= 14)    {
+            WriteByteDirect( size << 4 | getCompactType(elemType));
+        }
+        else {
+            WriteByteDirect( 0xf0 | getCompactType(elemType));
+            WriteVarint32( cast(size, UInt));
+        }
+    }
+
+    /**
+     * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+     */
+    private function WriteVarint64(n : haxe.Int64) : Void    {
+        var varint64out = new BytesBuffer();
+        while (true)
+        {
+            if( Int64.isZero( Int64.and( n, Int64.neg(Int64.make(0,0x7F)))))
+            {
+                varint64out.addByte( Int64.getLow(n));
+                break;
+            }
+            else
+            {
+                varint64out.addByte( (Int64.getLow(n) & 0x7F) | 0x80);
+                n = Int64.shr( n, 7);
+                n = Int64.and( n, Int64.make(0x01FFFFFF,0xFFFFFFFF));  // clean out the shifted 7 bits
+            }
+        }
+        var tmp = varint64out.getBytes();
+        trans.write( tmp, 0, tmp.length);
+    }
+
+
+    /**
+     * Read a message header.
+     */
+    public function readMessageBegin():TMessage {
+        Reset();
+
+        var protocolId : Int = readByte();
+        if (protocolId != PROTOCOL_ID) {
+            throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected protocol id " + StringTools.hex(PROTOCOL_ID,2) + " but got " + StringTools.hex(protocolId));
+        }
+
+        var versionAndType : Int = readByte();
+        var version : Int = (versionAndType & VERSION_MASK);
+        if (version != VERSION) {
+            throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected version " + VERSION + " but got " + version);
+        }
+
+        var type : Int = ((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+        var seqid : Int = cast( ReadVarint32(), Int);
+        var msgNm : String = readString();
+        return new TMessage( msgNm, type, seqid);
+    }
+
+    /**
+     * Read a struct begin. There's nothing on the wire for this, but it is our
+     * opportunity to push a new struct begin marker onto the field stack.
+     */
+    public function readStructBegin():TStruct {
+        lastField_.add(lastFieldId_);
+        lastFieldId_ = 0;
+        return ANONYMOUS_STRUCT;
+    }
+
+    /**
+     * Doesn't actually consume any wire data, just removes the last field for
+     * this struct from the field stack.
+     */
+    public function readStructEnd() : Void {
+        // consume the last field we Read off the wire.
+        lastFieldId_ = lastField_.pop();
+    }
+
+    /**
+     * Read a field header off the wire.
+     */
+    public function readFieldBegin() : TField {
+        var type : Int = readByte();
+
+        // if it's a stop, then we can return immediately, as the struct is over.
+        if (type == cast(TCompactTypes.STOP,Int)) {
+            return TSTOP;
+        }
+
+        var fieldId : Int;
+
+        // mask off the 4 MSB of the type header. it could contain a field id delta.
+        var modifier : Int = ((type & 0xf0) >> 4);
+        if (modifier == 0)
+            fieldId = readI16();  // not a delta. look ahead for the zigzag varint field id.
+        else
+            fieldId = lastFieldId_ + modifier; // add the delta to the last Read field id.
+
+        var field : TField  = new TField( "", cast(getTType(type & 0x0f),Int), fieldId);
+
+        // if this happens to be a boolean field, the value is encoded in the type
+        if (isBoolType(type)) {
+            // save the boolean value in a special instance variable.
+            boolValue_ = ((type & 0x0f) == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+        }
+
+        // push the new field onto the field stack so we can keep the deltas going.
+        lastFieldId_ = field.id;
+        return field;
+    }
+
+    /**
+     * Read a map header off the wire. If the size is zero, skip Reading the key
+     * and value type. This means that 0-length maps will yield TMaps without the
+     * "correct" types.
+     */
+    public function readMapBegin() : TMap {
+        var size : Int = cast( ReadVarint32(), Int);
+        var keyAndValueType : Int = ((size == 0)  ?  0  :  readByte());
+        var key : Int = cast( getTType( (keyAndValueType & 0xF0) >> 4), Int);
+        var val : Int = cast( getTType( keyAndValueType & 0x0F), Int);
+        return new TMap( key, val, size);
+    }
+
+    /**
+     * Read a list header off the wire. If the list size is 0-14, the size will
+     * be packed into the element type header. If it's a longer list, the 4 MSB
+     * of the element type header will be 0xF, and a varint will follow with the
+     * true size.
+     */
+    public function readListBegin():TList {
+        var size_and_type : Int = readByte();
+
+        var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+        if (size == 15) {
+            size = cast( ReadVarint32(), Int);
+        }
+
+        var type = getTType(size_and_type);
+        return new TList( type, size);
+    }
+
+    /**
+     * Read a set header off the wire. If the set size is 0-14, the size will
+     * be packed into the element type header. If it's a longer set, the 4 MSB
+     * of the element type header will be 0xF, and a varint will follow with the
+     * true size.
+     */
+    public function readSetBegin() : TSet {
+        var size_and_type : Int = readByte();
+
+        var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+        if (size == 15) {
+            size = cast( ReadVarint32(), Int);
+        }
+
+        var type = getTType(size_and_type);
+        return new TSet( type, size);
+    }
+
+    /**
+     * Read a boolean off the wire. If this is a boolean field, the value should
+     * already have been Read during ReadFieldBegin, so we'll just consume the
+     * pre-stored value. Otherwise, Read a byte.
+     */
+    public function readBool() : Bool {
+        if (boolValue_ != null) {
+            var result : Bool = boolValue_;
+            boolValue_ = null;
+            return result;
+        }
+
+        return (readByte() == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+    }
+
+    /**
+     * Read a single byte off the wire. Nothing interesting here.
+     */
+    public function readByte() : Int {
+        var byteRawBuf = new BytesBuffer();
+        trans.readAll( byteRawBuf, 0, 1);
+        return byteRawBuf.getBytes().get(0);
+    }
+
+    /**
+     * Read an i16 from the wire as a zigzag varint.
+     */
+    public function readI16() : Int {
+        return ZigZag.ToInt( ReadVarint32());
+    }
+
+    /**
+     * Read an i32 from the wire as a zigzag varint.
+     */
+    public function readI32() : Int {
+        return ZigZag.ToInt( ReadVarint32());
+    }
+
+    /**
+     * Read an i64 from the wire as a zigzag varint.
+     */
+    public function readI64() : haxe.Int64 {
+        return ZigZag.ToLong( ReadVarint64());
+    }
+
+    /**
+     * No magic here - just Read a double off the wire.
+     */
+    public function readDouble():Float {
+        var longBits = new BytesBuffer();
+        trans.readAll( longBits, 0, 8);
+        return BitConverter.Int64BitsToDouble( BitConverter.bytesToLong( longBits.getBytes()));
+    }
+
+    /**
+     * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+     */
+    public function readString() : String {
+        var length : Int = cast( ReadVarint32(), Int);
+
+        if (length == 0) {
+            return "";
+        }
+
+        var buf = new BytesBuffer();
+        trans.readAll( buf, 0, length);
+
+        length = buf.length;
+        var inp = new BytesInput( buf.getBytes());
+        var str = inp.readString( length);
+        if( utf8Strings)
+            return str;  // no need to decode on UTF8 targets, the string is just fine
+        else
+            return Utf8.decode( str);
+    }
+
+    /**
+     * Read a byte[] from the wire.
+     */
+    public function readBinary() : Bytes {
+        var length : Int = cast( ReadVarint32(), Int);
+        if (length == 0) {
+            return Bytes.alloc(0);
+        }
+
+        var buf = new BytesBuffer();
+        trans.readAll( buf, 0, length);
+        return buf.getBytes();
+    }
+
+
+    // These methods are here for the struct to call, but don't have any wire
+    // encoding.
+    public function readMessageEnd() : Void { }
+    public function readFieldEnd() : Void { }
+    public function readMapEnd() : Void { }
+    public function readListEnd() : Void { }
+    public function readSetEnd() : Void { }
+
+    //
+    // Internal Reading methods
+    //
+
+    /**
+     * Read an i32 from the wire as a varint. The MSB of each byte is set
+     * if there is another byte to follow. This can Read up to 5 bytes.
+     */
+    private function ReadVarint32() : UInt {
+        var result : UInt = 0;
+        var shift : Int = 0;
+        while (true) {
+            var b : Int = readByte();
+            result |= cast((b & 0x7f) << shift, UInt);
+            if ((b & 0x80) != 0x80) {
+                break;
+            }
+            shift += 7;
+        }
+        return result;
+    }
+
+    /**
+     * Read an i64 from the wire as a proper varint. The MSB of each byte is set
+     * if there is another byte to follow. This can Read up to 10 bytes.
+     */
+    private function ReadVarint64() : Int64 {
+        var shift : Int = 0;
+        var result : Int64 = Int64.make(0,0);
+        while (true) {
+            var b : Int = readByte();
+            result = Int64.or( result, Int64.shl( Int64.make(0,b & 0x7f), shift));
+            if ((b & 0x80) != 0x80) {
+                break;
+            }
+            shift += 7;
+        }
+
+        return result;
+    }
+
+
+    //
+    // type testing and converting
+    //
+
+    private function isBoolType( b : Int) : Bool {
+        var lowerNibble : Int = b & 0x0f;
+        switch(lowerNibble)
+        {
+            case TCompactTypes.BOOLEAN_TRUE: return true;
+            case TCompactTypes.BOOLEAN_FALSE: return true;
+            default: return false;
+        }
+    }
+
+
+    /**
+     * Given a TCompactProtocol.TCompactTypes constant, convert it to its corresponding
+     * TType value.
+     */
+    private function getTType( type : Int) : Int {
+        try
+        {
+            return tcompactTypeToType[type];
+            throw "fuck";
+        }
+        catch ( e : Dynamic)
+        {
+            var tt : Int = (type & 0x0f);
+            throw new TProtocolException( TProtocolException.UNKNOWN, 'don\'t know what type: $tt ($e)');
+        }
+    }
+
+    /**
+     * Given a TType value, find the appropriate TCompactProtocol.TCompactTypes constant.
+     */
+    private function getCompactType( ttype : Int) : Int
+    {
+        return cast( ttypeToCompactType[ttype], Int);
+    }
+}

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
----------------------------------------------------------------------
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
new file mode 100644
index 0000000..c5673b4
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* Compact Protocol Factory
+*/
+class TCompactProtocolFactory implements TProtocolFactory {
+
+    public function new() {
+    }
+
+    public function getProtocol( trans : TTransport) : TProtocol  {
+        return new TCompactProtocol( trans);
+    }
+}
+
+
+
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/test/haxe/src/Arguments.hx
----------------------------------------------------------------------
diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx
index 132f208..cae91df 100644
--- a/test/haxe/src/Arguments.hx
+++ b/test/haxe/src/Arguments.hx
@@ -32,6 +32,7 @@ using StringTools;
 enum ProtocolType {
     binary;
     json;
+    compact;
 }
 
 enum EndpointTransport {
@@ -190,7 +191,7 @@ class Arguments
                 if( arg == "binary") {
                     protocol = binary;
                 } else if( arg == "compact") {
-                    throw "Compact protocol not supported yet";
+                    protocol = compact;
                 } else if( arg == "json") {
                     protocol = json;
                 } else {

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/test/haxe/src/TestClient.hx
----------------------------------------------------------------------
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
index f77620f..5193c47 100644
--- a/test/haxe/src/TestClient.hx
+++ b/test/haxe/src/TestClient.hx
@@ -214,13 +214,15 @@ class TestClient {
         case json:
             trace("- json protocol");
             protocol = new TJSONProtocol(transport);
-        default:
-            throw "Unhandled protocol";
+        case compact:
+            trace("- compact protocol");
+            protocol = new TCompactProtocol(transport);
         }
 
 
         // run the test code
         HaxeBasicsTest( args, rslt);
+        ModuleUnitTests( args, rslt);
         for( i in 0 ... args.numIterations) {
             ClientTest( transport, protocol, args, rslt);
         }
@@ -244,107 +246,132 @@ class TestClient {
         map32.set( 42, 815);
         map64.set( Int64.make(0,42), 815);
         map32.set( -517, 23);
-        map64.set( Int64.make(-5,17), 23);
+        map64.set( Int64.neg(Int64.make(0,517)), 23);
         map32.set( 0, -123);
         map64.set( Int64.make(0,0), -123);
 
         rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #10");
         rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #11");
-        rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #12");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #12");
         rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #13");
         rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #14");
         rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #15");
-        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #16");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #16");
         rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #Int64.make(-5,17)");
         rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #18");
         rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #19");
-        rslt.Expect( map32.remove( -517) == map64.remove( Int64.make(-5,17)), "Int64Map<Int32> Test #20");
+        rslt.Expect( map32.remove( -517) == map64.remove( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #20");
         rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #21");
-        rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #22");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #22");
         rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #23");
         rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #24");
         rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #25");
-        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #26");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #26");
         rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #27");
         rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #28");
 
         map32.set( 42, 1);
         map64.set( Int64.make(0,42), 1);
         map32.set( -517, -2);
-        map64.set( Int64.make(-5,17), -2);
+        map64.set( Int64.neg(Int64.make(0,517)), -2);
         map32.set( 0, 3);
         map64.set( Int64.make(0,0), 3);
 
         var c32 = 0;
+        var ksum32 = 0;
         for (key in map32.keys()) {
             ++c32;
+            ksum32 += key;
         }
         var c64 = 0;
+        var ksum64 = Int64.make(0,0);
         for (key in map64.keys()) {
             ++c64;
+            ksum64 = Int64.add( ksum64, key);
         }
         rslt.Expect( c32 == c64, "Int64Map<Int32> Test #30");
+        rslt.Expect( '$ksum64' == '$ksum32', '$ksum64 == $ksum32   Test #31');
 
         var s32 = map32.toString();
         var s64 = map64.toString();
-        trace("Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64")');
+        rslt.Expect( s32 == s64, "Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64") Test #32');
 
         map32.remove( 42);
         map64.remove( Int64.make(0,42));
         map32.remove( -517);
-        map64.remove( Int64.make(-5,17));
+        map64.remove( Int64.neg(Int64.make(0,517)));
         map32.remove( 0);
         map64.remove( Int64.make(0,0));
 
         rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #90");
         rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #91");
-        rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #92");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #92");
         rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #93");
         rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #94");
         rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #95");
         rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #96");
         rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #97");
-        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #98");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0, 0)), "Int64Map<Int32> Test #98");
+    }
+
+
+    // core module unit tests
+    public static function ModuleUnitTests( args : Arguments, rslt : TestResults) : Void {
+        try {
+            BitConverter.UnitTest();
+            rslt.Expect( true, 'BitConverter.UnitTest  Test #100');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'BitConverter.UnitTest: $e  Test #100');
+        }
+
+        try {
+            ZigZag.UnitTest();
+            rslt.Expect( true, 'ZigZag.UnitTest  Test #101');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
+        }
+    }
+
+
+    public static function BytesToHex(data : Bytes) : String {
+        var hex = "";
+        for ( i in 0 ... data.length) {
+            hex += StringTools.hex( data.get(i), 2);
+        }
+        return hex;
+    }
+
+    public static function PrepareTestData(randomDist : Bool) : Bytes    {
+        var retval = Bytes.alloc(0x100);
+        var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);
+
+        // linear distribution, unless random is requested
+        if (!randomDist) {
+            for (i in 0 ... initLen) {
+                retval.set(i, i % 0x100);
+            }
+            return retval;
+        }
+
+        // random distribution
+        for (i in 0 ... initLen) {
+            retval.set(i, 0);
+        }
+        for (i in 1 ... initLen) {
+            while( true) {
+                var nextPos = Std.random(initLen);
+                if (retval.get(nextPos) == 0) {
+                    retval.set( nextPos, i % 0x100);
+                    break;
+                }
+            }
+        }
+        return retval;
     }
 
 
-	public static function BytesToHex(data : Bytes) : String {
-		var hex = "";
-		for ( i in 0 ... data.length) {
-			hex += StringTools.hex( data.get(i), 2);
-		}
-		return hex;
-	}
-
-	public static function PrepareTestData(randomDist : Bool) : Bytes	{
-		var retval = Bytes.alloc(0x100);
-		var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);
-
-		// linear distribution, unless random is requested
-		if (!randomDist) {
-			for (i in 0 ... initLen) { 
-				retval.set(i, i % 0x100);
-			}
-			return retval;
-		}
-
-		// random distribution
-		for (i in 0 ... initLen) { 
-			retval.set(i, 0);
-		}
-		for (i in 1 ... initLen) { 
-			while( true) {
-				var nextPos = Std.random(initLen);
-				if (retval.get(nextPos) == 0) {
-					retval.set( nextPos, i % 0x100);
-					break;
-				}
-			}
-		}
-		return retval;
-	}
-
-	
     public static function ClientTest( transport : TTransport, protocol : TProtocol,
                                        args : Arguments, rslt : TestResults) : Void
     {
@@ -402,6 +429,11 @@ class TestClient {
             rslt.Expect( false, 'testException("TException")  -  $e');
         }
 
+        // reopen the transport, just in case the server closed his end
+        if (transport.isOpen())
+            transport.close();
+        transport.open();
+
         // else do not throw anything
         trace('testException("bla")');
         try {
@@ -413,8 +445,6 @@ class TestClient {
             rslt.Expect( false, 'testException("bla")  -  $e');
         }
 
-
-
         rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
 
         trace('testVoid()');
@@ -459,16 +489,16 @@ class TestClient {
         trace('testBinary('+BytesToHex(binOut)+')');
         try {
             var binIn = client.testBinary(binOut);
-			trace('testBinary() = '+BytesToHex(binIn));
-			rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
-			var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
+            trace('testBinary() = '+BytesToHex(binIn));
+            rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
+            var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
             for (ofs in 0 ... len) {
                 if (binIn.get(ofs) != binOut.get(ofs)) {
-					rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
-				}
-			}
-		}
-		catch (e : TApplicationException) {
+                    rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
+                }
+            }
+        }
+        catch (e : TApplicationException) {
             trace('testBinary('+BytesToHex(binOut)+'): '+e.errorMsg);  // may not be supported by the server
         }
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/test/haxe/src/TestMacro.hx
----------------------------------------------------------------------
diff --git a/test/haxe/src/TestMacro.hx b/test/haxe/src/TestMacro.hx
index 0129d3f..a620760 100644
--- a/test/haxe/src/TestMacro.hx
+++ b/test/haxe/src/TestMacro.hx
@@ -24,10 +24,10 @@ import haxe.macro.Expr;
 
 /****
  * If you call the Thrift compiler this way (e.g. by changing the prebuild command)
- * 
+ *
  *     thrift -r -gen haxe:buildmacro=TestMacro.handle()   ../ThriftTest.thrift
- * 
- * the TestMacro.handle() function implemented below is called for each generated class 
+ *
+ * the TestMacro.handle() function implemented below is called for each generated class
  * and interface. Use "thrift --help" to get more info about other available options.
  */
 class TestMacro
@@ -36,5 +36,5 @@ class TestMacro
     trace('TestMacro called for ' + Context.getLocalType());
     return Context.getBuildFields();
   }
-  
+
 }

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/test/haxe/src/TestServer.hx
----------------------------------------------------------------------
diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx
index 502d0d1..4490a8c 100644
--- a/test/haxe/src/TestServer.hx
+++ b/test/haxe/src/TestServer.hx
@@ -69,8 +69,9 @@ class TestServer
             case json:
                 trace("- json protocol");
                 protfactory = new TJSONProtocolFactory();
-            default:
-                throw "Unhandled protocol";
+            case compact:
+                trace("- compact protocol");
+                protfactory = new TCompactProtocolFactory();
             }
 
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/426ab868/test/haxe/src/TestServerHandler.hx
----------------------------------------------------------------------
diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx
index 9e2a633..abcef13 100644
--- a/test/haxe/src/TestServerHandler.hx
+++ b/test/haxe/src/TestServerHandler.hx
@@ -120,19 +120,19 @@ class TestServerHandler implements ThriftTest {
      * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
      * @param binary  thing - the binary data to print
      * @return binary  - returns the binary 'thing'
-     * 
+     *
      * @param thing
      */
     public function testBinary(thing : haxe.io.Bytes) : haxe.io.Bytes
     {
-		var hex = "";
-		for ( i in 0 ... thing.length) {
-			hex += StringTools.hex( thing.get(i), 2);
-		}
+        var hex = "";
+        for ( i in 0 ... thing.length) {
+            hex += StringTools.hex( thing.get(i), 2);
+        }
         trace('testBinary($hex)');
         return thing;
     }
-  
+
     /**
     * Prints 'testStruct("{%s}")' where thing has been formatted
     *  into a string of comma separated values