# 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/cpp/src/Slice/PythonUtil.cpp Ice-3.4.2/cpp/src/Slice/PythonUtil.cpp
--- Ice-3.4.2.orig/cpp/src/Slice/PythonUtil.cpp	2011-06-15 12:43:59.000000000 -0700
+++ Ice-3.4.2/cpp/src/Slice/PythonUtil.cpp	2013-01-31 10:50:29.000000000 -0800
@@ -1320,9 +1320,11 @@
 Slice::Python::CodeVisitor::visitSequence(const SequencePtr& p)
 {
     static const string protobuf = "python:protobuf:";
+    static const string thrift = "python:thrift:";
     StringList metaData = p->getMetaData();
     bool isCustom = false;
     string customType;
+    string encoder;
     for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q)
     {
         if(q->find(protobuf) == 0)
@@ -1334,6 +1336,19 @@
             }
             isCustom = true;
             customType = q->substr(protobuf.size());
+            encoder = "protobuf";
+            break;
+        }
+        else if(q->find(thrift) == 0)
+        {
+            BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type());
+            if(!builtin || builtin->kind() != Builtin::KindByte)
+            {
+                continue;
+            }
+            isCustom = true;
+            customType = q->substr(thrift.size());
+            encoder = "thrift";
             break;
         }
     }
@@ -1346,10 +1361,10 @@
     _out.inc();
     if(isCustom)
     {
-        string package = customType.substr(0, customType.find('.'));
+        string package = customType.substr(0, customType.rfind('.'));
         _out << nl << "import " << package;
         _out << nl << "_M_" << getAbsolute(p, "_t_")
-             << " = IcePy.defineCustom('" << scoped << "', " << customType << ")";
+             << " = IcePy.defineCustom('" << scoped << "', " << customType << ", '" << encoder << "')";
     }
     else
     {
@@ -2456,6 +2471,7 @@
 Slice::Python::MetaDataVisitor::visitSequence(const SequencePtr& p)
 {
     static const string protobuf = "python:protobuf:";
+    static const string thrift = "python:thrift:";
     StringList metaData = p->getMetaData();
     const string file = p->file();
     const string line = p->line();
@@ -2476,6 +2492,20 @@
                             "`protobuf' encoding must be a byte sequence");
             }
         }
+        else if(s.find(thrift) == 0)
+        {
+            //
+            // Remove from list so validateSequence does not try to handle as well.
+            //
+            metaData.remove(s);
+
+            BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type());
+            if(!builtin || builtin->kind() != Builtin::KindByte)
+            {
+                emitWarning(file, line, "ignoring invalid metadata `" + s + ": " +
+                            "`thrift' encoding must be a byte sequence");
+            }
+        }
     }
 
     validateSequence(file, line, p, metaData);
diff -ru Ice-3.4.2.orig/py/modules/IcePy/Types.cpp Ice-3.4.2/py/modules/IcePy/Types.cpp
--- Ice-3.4.2.orig/py/modules/IcePy/Types.cpp	2011-06-15 12:44:00.000000000 -0700
+++ Ice-3.4.2/py/modules/IcePy/Types.cpp	2013-01-31 10:50:29.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 Ice-3.4.2/py/modules/IcePy/Types.h
--- Ice-3.4.2.orig/py/modules/IcePy/Types.h	2011-06-15 12:44:00.000000000 -0700
+++ Ice-3.4.2/py/modules/IcePy/Types.h	2013-01-31 10:50:29.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;
 
