# Patch to support Thrift as a data interchange format in the same
# manner as Ice supports Google Protocol Buffers.
#
# Patch by: J Robert Ray jrray{_at_}imageworks{_dot_}com

diff -ru ../Ice-3.4.2.orig/py/modules/IcePy/Types.cpp ./py/modules/IcePy/Types.cpp
--- ../Ice-3.4.2.orig/py/modules/IcePy/Types.cpp	2011-06-15 12:44:00.000000000 -0700
+++ ./py/modules/IcePy/Types.cpp	2013-01-31 11:20:55.000000000 -0800
@@ -1877,22 +1877,55 @@
 {
     assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this.
 
-    PyObjectHandle obj = PyObject_CallMethod(p, STRCAST("IsInitialized"), 0);
-    if(!obj.get())
-    {
-        throwPythonException();
-    }
-    if(!PyObject_IsTrue(obj.get()))
-    {
-        setPythonException(Ice::MarshalException(__FILE__, __LINE__, "type not fully initialized"));
-        throw AbortMarshaling();
+    PyObjectHandle obj;
+
+    if (thrift) {
+        PyObjectHandle transportOut = PyObject_Call(TMemoryBuffer.get(), emptyTuple.get(), NULL);
+        if (!transportOut.get()) {
+            throwPythonException();
+        }
+
+        PyObjectHandle tup = PyTuple_New(1);
+        if (!tup.get()) {
+            throwPythonException();
+        }
+        Py_INCREF(transportOut.get());
+        PyTuple_SET_ITEM(tup.get(), 0, transportOut.get());
+
+        PyObjectHandle protocolOut = PyObject_Call(TBinaryProtocol.get(), tup.get(), NULL);
+        if (!protocolOut.get()) {
+            throwPythonException();
+        }
+
+        obj = PyObject_CallMethodObjArgs(p, writeStr.get(), protocolOut.get(), NULL);
+        if (!obj.get()) {
+            throwPythonException();
+        }
+
+        obj = PyObject_CallMethodObjArgs(transportOut.get(), getvalueStr.get(), NULL);
+        if (!obj.get()) {
+            assert(PyErr_Occurred());
+            throw AbortMarshaling();
+        }
     }
+    else {
+        PyObjectHandle obj = PyObject_CallMethod(p, STRCAST("IsInitialized"), 0);
+        if(!obj.get())
+        {
+            throwPythonException();
+        }
+        if(!PyObject_IsTrue(obj.get()))
+        {
+            setPythonException(Ice::MarshalException(__FILE__, __LINE__, "type not fully initialized"));
+            throw AbortMarshaling();
+        }
 
-    obj = PyObject_CallMethod(p, STRCAST("SerializeToString"), 0);
-    if(!obj.get())
-    {
-        assert(PyErr_Occurred());
-        throw AbortMarshaling();
+        obj = PyObject_CallMethod(p, STRCAST("SerializeToString"), 0);
+        if(!obj.get())
+        {
+            assert(PyErr_Occurred());
+            throw AbortMarshaling();
+        }
     }
 
     assert(PyString_Check(obj.get()));
@@ -1913,16 +1946,10 @@
     int sz = static_cast<int>(seq.second - seq.first);
 
     //
-    // Create a new instance of the protobuf type.
+    // Create a new instance of the protobuf/thrift type.
     //
-    PyObjectHandle args = PyTuple_New(0);
-    if(!args.get())
-    {
-        assert(PyErr_Occurred());
-        throw AbortMarshaling();
-    }
     PyTypeObject* type = reinterpret_cast<PyTypeObject*>(pythonType.get());
-    PyObjectHandle p = type->tp_new(type, args.get(), 0);
+    PyObjectHandle p = type->tp_new(type, emptyTuple.get(), 0);
     if(!p.get())
     {
         assert(PyErr_Occurred());
@@ -1932,7 +1959,7 @@
     //
     // Initialize the object.
     //
-    PyObjectHandle obj = PyObject_CallMethod(p.get(), STRCAST("__init__"), 0, 0);
+    PyObjectHandle obj = PyObject_CallMethodObjArgs(p.get(), initStr.get(), NULL);
     if(!obj.get())
     {
         assert(PyErr_Occurred());
@@ -1949,14 +1976,45 @@
         throw AbortMarshaling();
     }
 
-    //
-    // Parse the string.
-    //
-    obj = PyObject_CallMethod(p.get(), STRCAST("ParseFromString"), STRCAST("O"), obj.get(), 0);
-    if(!obj.get())
-    {
-        assert(PyErr_Occurred());
-        throw AbortMarshaling();
+    if (thrift) {
+        PyObjectHandle tup = PyTuple_New(1);
+        if (!tup.get()) {
+            throwPythonException();
+        }
+        PyTuple_SET_ITEM(tup.get(), 0, obj.release());
+
+        PyObjectHandle transportIn = PyObject_Call(TMemoryBuffer.get(), tup.get(), NULL);
+        if (!transportIn.get()) {
+            throwPythonException();
+        }
+
+        tup = PyTuple_New(1);
+        if (!tup.get()) {
+            throwPythonException();
+        }
+        PyTuple_SET_ITEM(tup.get(), 0, transportIn.release());
+
+        PyObjectHandle protocolIn = PyObject_Call(TBinaryProtocol.get(), tup.get(), NULL);
+        if (!protocolIn.get()) {
+            throwPythonException();
+        }
+
+        obj = PyObject_CallMethodObjArgs(p.get(), readStr.get(), protocolIn.get(), NULL);
+        if (!obj.get()) {
+            assert(PyErr_Occurred());
+            throw AbortMarshaling();
+        }
+    }
+    else {
+        //
+        // Parse the string.
+        //
+        obj = PyObject_CallMethod(p.get(), STRCAST("ParseFromString"), STRCAST("O"), obj.get(), 0);
+        if(!obj.get())
+        {
+            assert(PyErr_Occurred());
+            throw AbortMarshaling();
+        }
     }
 
     cb->unmarshaled(p.get(), target, closure);
@@ -3213,7 +3271,8 @@
 {
     char* id;
     PyObject* type;
-    if(!PyArg_ParseTuple(args, STRCAST("sO"), &id, &type))
+    char* encoder;
+    if(!PyArg_ParseTuple(args, STRCAST("sOs"), &id, &type, &encoder))
     {
         return 0;
     }
@@ -3223,6 +3282,52 @@
     CustomInfoPtr info = new CustomInfo;
     info->id = id;
     info->pythonType = type;
+    if (!strncmp(encoder, "thrift", 6)) {
+        info->thrift = true;
+
+        PyObjectHandle TTransport = PyImport_ImportModule(STRCAST("thrift.transport.TTransport"));
+        if (!TTransport.get()) {
+            throwPythonException();
+        }
+        info->TMemoryBuffer = PyObject_GetAttrString(TTransport.get(), STRCAST("TMemoryBuffer"));
+        if (!info->TMemoryBuffer.get()) {
+            throwPythonException();
+        }
+
+        PyObjectHandle TBinaryProtocol = PyImport_ImportModule(STRCAST("thrift.protocol.TBinaryProtocol"));
+        if (!TBinaryProtocol.get()) {
+            throwPythonException();
+        }
+        info->TBinaryProtocol = PyObject_GetAttrString(TBinaryProtocol.get(), STRCAST("TBinaryProtocol"));
+        if (!info->TBinaryProtocol.get()) {
+            throwPythonException();
+        }
+
+        info->readStr = PyString_FromStringAndSize(STRCAST("read"), 4);
+        if (!info->readStr.get()) {
+            throwPythonException();
+        }
+
+        info->writeStr = PyString_FromStringAndSize(STRCAST("write"), 5);
+        if (!info->writeStr.get()) {
+            throwPythonException();
+        }
+
+        info->getvalueStr = PyString_FromStringAndSize(STRCAST("getvalue"), 8);
+        if (!info->getvalueStr.get()) {
+            throwPythonException();
+        }
+    }
+
+    info->emptyTuple = PyTuple_New(0);
+    if (!info->emptyTuple.get()) {
+        throwPythonException();
+    }
+
+    info->initStr = PyString_FromStringAndSize(STRCAST("__init__"), 8);
+    if (!info->initStr.get()) {
+        throwPythonException();
+    }
 
     return createType(info);
 }
diff -ru ../Ice-3.4.2.orig/py/modules/IcePy/Types.h ./py/modules/IcePy/Types.h
--- ../Ice-3.4.2.orig/py/modules/IcePy/Types.h	2011-06-15 12:44:00.000000000 -0700
+++ ./py/modules/IcePy/Types.h	2013-01-31 11:20:55.000000000 -0800
@@ -271,6 +271,14 @@
 
     std::string id;
     PyObjectHandle pythonType;
+    bool thrift;
+    PyObjectHandle TMemoryBuffer;
+    PyObjectHandle TBinaryProtocol;
+    PyObjectHandle emptyTuple;
+    PyObjectHandle readStr;
+    PyObjectHandle writeStr;
+    PyObjectHandle getvalueStr;
+    PyObjectHandle initStr;
 };
 typedef IceUtil::Handle<CustomInfo> CustomInfoPtr;
 
