diff options
author | Mark Spruiell <mes@zeroc.com> | 2006-08-24 23:00:10 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2006-08-24 23:00:10 +0000 |
commit | c8d6203027334c6ca01aa75bb799b52c4924b102 (patch) | |
tree | ed4c7e774d7a4d20573b1de660041115f952bb96 /py | |
parent | bug 1316: auto_array (diff) | |
download | ice-c8d6203027334c6ca01aa75bb799b52c4924b102.tar.bz2 ice-c8d6203027334c6ca01aa75bb799b52c4924b102.tar.xz ice-c8d6203027334c6ca01aa75bb799b52c4924b102.zip |
bug 943: map sequence<byte> to string
Diffstat (limited to 'py')
-rw-r--r-- | py/CHANGES | 65 | ||||
-rw-r--r-- | py/modules/IcePy/.depend | 27 | ||||
-rw-r--r-- | py/modules/IcePy/Operation.cpp | 122 | ||||
-rw-r--r-- | py/modules/IcePy/Types.cpp | 478 | ||||
-rw-r--r-- | py/modules/IcePy/Types.h | 69 | ||||
-rw-r--r-- | py/modules/IcePy/Util.cpp | 46 | ||||
-rw-r--r-- | py/modules/IcePy/Util.h | 5 | ||||
-rw-r--r-- | py/python/Ice.py | 12 | ||||
-rw-r--r-- | py/test/Ice/custom/AllTests.py | 108 | ||||
-rw-r--r-- | py/test/Ice/custom/Client.py | 46 | ||||
-rw-r--r-- | py/test/Ice/custom/Server.py | 113 | ||||
-rw-r--r-- | py/test/Ice/custom/Test.ice | 70 | ||||
-rwxr-xr-x | py/test/Ice/custom/run.py | 26 | ||||
-rw-r--r-- | py/test/Ice/operations/Twoways.py | 100 |
14 files changed, 1006 insertions, 281 deletions
diff --git a/py/CHANGES b/py/CHANGES index 4e363bd94d4..530572a968e 100644 --- a/py/CHANGES +++ b/py/CHANGES @@ -1,3 +1,60 @@ +NOTE: Please keep changes in the appropriate section for HEAD or 3.1. + +Changes since version 3.1.1 +--------------------------- + +- Added support for metadata to modify the mapping of a Slice + sequence type. The default mapping for sequences remains unchanged + (except for sequence<byte> as described below): a sequence is + received as a Python list. Using metadata, you can now specify that + a sequence be received as a tuple instead: + + ["python:seq:tuple"] sequence<string> StringTuple; + + In this example, all occurrences of StringTuple are received as + a tuple. You can also apply the metadata more selectively: + + sequence<string> StringList; + struct S { + StringList l; + ["python:seq:tuple"] StringList stringTuple; + }; + interface I { + ["python:seq:tuple"] StringList op(StringList l); + }; + + In this case, the default mapping is used for all occurrences of + StringList except for the stringTuple member of the structure and + the return value of op(). + + The metadata "python:seq:list" forces a sequence to be received + as a list, which you can use to override a prior metadata + definition: + + ["python:seq:tuple"] sequence<string> StringTuple; + struct S { + ["python:seq:list"] StringTuple stringList; + }; + + Finally, the metadata "python:seq:default" directs the extension + to use the default mapping for the sequence, which is a list for all + sequence types except sequence<byte>. + +- The default mapping for the Slice type sequence<byte> is now a + Python string, and therefore a string is also accepted as a legal + value for sequence<byte>. For programs that need to continue + receiving a sequence<byte> value as a list, you can use a metadata + directive to modify the mapping as shown below: + + ["python:seq:list"] sequence<byte> ByteList; + +- The extension now accepts an object that implements the buffer + protocol as a legal value for sequences of most primitive types. + For example, it is more efficient to transfer an array of integer + values constructed using the "array" module than it is using a tuple + or a list. Note that no type- or range-checking is performed on the + contents of a buffer. + Changes since version 3.1.0 --------------------------- @@ -5,13 +62,13 @@ Changes since version 3.1.0 where the session would not be destroyed in the event of an allocation failure. --- Added UnexpectedObjectException. This exception is raised if you +- Added UnexpectedObjectException. This exception is raised if you use Slice classes and client and server are compiled with mismatched Slice definitions. Alternatively, this exception is raised if you - use dynamic invocation and pass a class of the wrong type as an operation - parameter. + use dynamic invocation and pass a class of the wrong type as an + operation parameter. -- Restored Communicator::setDefaultContext +- Restored Communicator::setDefaultContext. Changes since version 3.0.1 --------------------------- diff --git a/py/modules/IcePy/.depend b/py/modules/IcePy/.depend index dfe6878a40c..9e75a745408 100644 --- a/py/modules/IcePy/.depend +++ b/py/modules/IcePy/.depend @@ -1,13 +1,14 @@ -Communicator.o: Communicator.cpp Communicator.h Config.h Logger.h Util.h ObjectAdapter.h ObjectFactory.h Properties.h Proxy.h -Connection.o: Connection.cpp Connection.h Config.h ObjectAdapter.h Proxy.h Util.h -Current.o: Current.cpp Current.h Config.h Connection.h ObjectAdapter.h Util.h -Init.o: Init.cpp Communicator.h Config.h Connection.h Current.h Logger.h Util.h ObjectAdapter.h Operation.h Properties.h Proxy.h Slice.h Types.h -Logger.o: Logger.cpp Logger.h Config.h Util.h -ObjectAdapter.o: ObjectAdapter.cpp ObjectAdapter.h Config.h Communicator.h Current.h Operation.h Proxy.h Util.h -ObjectFactory.o: ObjectFactory.cpp ObjectFactory.h Config.h Types.h Util.h -Operation.o: Operation.cpp Operation.h Config.h Current.h Proxy.h Types.h Util.h -Properties.o: Properties.cpp Properties.h Config.h Util.h -Proxy.o: Proxy.cpp Proxy.h Config.h Communicator.h Connection.h Util.h -Slice.o: Slice.cpp Slice.h Config.h Util.h -Types.o: Types.cpp Types.h Config.h Util.h Current.h Proxy.h -Util.o: Util.cpp Util.h Config.h +Communicator.o: Communicator.cpp ./Communicator.h ./Config.h ./Logger.h ./Util.h ./ObjectAdapter.h ./ObjectFactory.h ./Properties.h ./Proxy.h ./ThreadNotification.h +Connection.o: Connection.cpp ./Connection.h ./Config.h ./ObjectAdapter.h ./Proxy.h ./Util.h +Current.o: Current.cpp ./Current.h ./Config.h ./Connection.h ./ObjectAdapter.h ./Util.h +Init.o: Init.cpp ./Communicator.h ./Config.h ./Connection.h ./Current.h ./Logger.h ./Util.h ./ObjectAdapter.h ./Operation.h ./Properties.h ./Proxy.h ./Slice.h ./Types.h +Logger.o: Logger.cpp ./Logger.h ./Config.h ./Util.h +ObjectAdapter.o: ObjectAdapter.cpp ./ObjectAdapter.h ./Config.h ./Communicator.h ./Current.h ./Operation.h ./Proxy.h ./Util.h +ObjectFactory.o: ObjectFactory.cpp ./ObjectFactory.h ./Config.h ./Types.h ./Util.h +Operation.o: Operation.cpp ./Operation.h ./Config.h ./Current.h ./Proxy.h ./Types.h ./Util.h +Properties.o: Properties.cpp ./Properties.h ./Config.h ./Util.h +Proxy.o: Proxy.cpp ./Proxy.h ./Config.h ./Communicator.h ./Connection.h ./Util.h +Slice.o: Slice.cpp ./Slice.h ./Config.h ./Util.h +ThreadNotification.o: ThreadNotification.cpp ./ThreadNotification.h ./Config.h ./Util.h +Types.o: Types.cpp ./Types.h ./Config.h ./Util.h ./Current.h ./Proxy.h +Util.o: Util.cpp ./Util.h ./Config.h diff --git a/py/modules/IcePy/Operation.cpp b/py/modules/IcePy/Operation.cpp index 177d3e25557..1808fdc96fa 100644 --- a/py/modules/IcePy/Operation.cpp +++ b/py/modules/IcePy/Operation.cpp @@ -38,6 +38,7 @@ public: virtual void unmarshaled(PyObject*, PyObject*, void*); + Ice::StringSeq metaData; TypeInfoPtr type; }; typedef IceUtil::Handle<ParamInfo> ParamInfoPtr; @@ -47,7 +48,7 @@ class OperationI : public Operation { public: - OperationI(const char*, PyObject*, PyObject*, int, PyObject*, PyObject*, PyObject*, PyObject*); + OperationI(const char*, PyObject*, PyObject*, int, PyObject*, PyObject*, PyObject*, PyObject*, PyObject*); virtual PyObject* invoke(const Ice::ObjectPrx&, PyObject*, PyObject*); virtual PyObject* invokeAsync(const Ice::ObjectPrx&, PyObject*, PyObject*, PyObject*); @@ -69,6 +70,7 @@ private: Ice::OperationMode _mode; Ice::OperationMode _sendMode; bool _amd; + Ice::StringSeq _metaData; ParamInfoList _inParams; ParamInfoList _outParams; ParamInfoPtr _returnType; @@ -83,6 +85,7 @@ private: PyObject* unmarshalException(const vector<Ice::Byte>&, const Ice::CommunicatorPtr&); bool validateException(PyObject*) const; void checkTwowayOnly(const Ice::ObjectPrx&) const; + static void convertParams(PyObject*, ParamInfoList&, bool&); }; typedef IceUtil::Handle<OperationI> OperationIPtr; @@ -149,17 +152,19 @@ operationInit(OperationObject* self, PyObject* args, PyObject* /*kwds*/) PyObject* mode; PyObject* sendMode; int amd; + PyObject* meta; PyObject* inParams; PyObject* outParams; PyObject* returnType; PyObject* exceptions; - if(!PyArg_ParseTuple(args, STRCAST("sO!O!iO!O!OO!"), &name, modeType, &mode, modeType, &sendMode, &amd, - &PyTuple_Type, &inParams, &PyTuple_Type, &outParams, &returnType, &PyTuple_Type, &exceptions)) + if(!PyArg_ParseTuple(args, STRCAST("sO!O!iO!O!O!OO!"), &name, modeType, &mode, modeType, &sendMode, &amd, + &PyTuple_Type, &meta, &PyTuple_Type, &inParams, &PyTuple_Type, &outParams, &returnType, + &PyTuple_Type, &exceptions)) { return -1; } - OperationIPtr op = new OperationI(name, mode, sendMode, amd, inParams, outParams, returnType, exceptions); + OperationIPtr op = new OperationI(name, mode, sendMode, amd, meta, inParams, outParams, returnType, exceptions); self->op = new OperationPtr(op); return 0; @@ -394,19 +399,10 @@ IcePy::AMICallback::ice_exception(const Ice::Exception& ex) // // OperationI implementation. // -IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMode, int amd, PyObject* inParams, - PyObject* outParams, PyObject* returnType, PyObject* exceptions) +IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMode, int amd, PyObject* meta, + PyObject* inParams, PyObject* outParams, PyObject* returnType, PyObject* exceptions) { _name = name; - _amd = amd ? true : false; - if(_amd) - { - _dispatchName = fixIdent(_name) + "_async"; - } - else - { - _dispatchName = fixIdent(_name); - } // // mode @@ -422,39 +418,39 @@ IcePy::OperationI::OperationI(const char* name, PyObject* mode, PyObject* sendMo assert(PyInt_Check(sendModeValue.get())); _sendMode = (Ice::OperationMode)static_cast<int>(PyInt_AS_LONG(sendModeValue.get())); + // + // amd + // + _amd = amd ? true : false; + if(_amd) + { + _dispatchName = fixIdent(_name) + "_async"; + } + else + { + _dispatchName = fixIdent(_name); + } + + // + // metaData + // +#ifndef NDEBUG + bool b = +#endif + tupleToStringSeq(meta, _metaData); + assert(b); + int i, sz; // // inParams // - _sendsClasses = false; - sz = PyTuple_GET_SIZE(inParams); - for(i = 0; i < sz; ++i) - { - ParamInfoPtr param = new ParamInfo; - param->type = getType(PyTuple_GET_ITEM(inParams, i)); - _inParams.push_back(param); - if(!_sendsClasses) - { - _sendsClasses = param->type->usesClasses(); - } - } + convertParams(inParams, _inParams, _sendsClasses); // // outParams // - _returnsClasses = false; - sz = PyTuple_GET_SIZE(outParams); - for(i = 0; i < sz; ++i) - { - ParamInfoPtr param = new ParamInfo; - param->type = getType(PyTuple_GET_ITEM(outParams, i)); - _outParams.push_back(param); - if(!_returnsClasses) - { - _returnsClasses = param->type->usesClasses(); - } - } + convertParams(outParams, _outParams, _returnsClasses); // // returnType @@ -708,7 +704,7 @@ IcePy::OperationI::dispatch(PyObject* servant, const Ice::AMD_Object_ice_invokeP for(ParamInfoList::iterator p = _inParams.begin(); p != _inParams.end(); ++p, ++i) { void* closure = reinterpret_cast<void*>(i); - (*p)->type->unmarshal(is, *p, args.get(), closure); + (*p)->type->unmarshal(is, *p, args.get(), closure, &(*p)->metaData); } if(_sendsClasses) { @@ -923,7 +919,7 @@ IcePy::OperationI::sendResponse(const Ice::AMD_Object_ice_invokePtr& cb, PyObjec PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); throw Ice::MarshalException(__FILE__, __LINE__); } - (*p)->type->marshal(arg, os, &objectMap); + (*p)->type->marshal(arg, os, &objectMap, &(*p)->metaData); } if(_returnType) @@ -946,7 +942,7 @@ IcePy::OperationI::sendResponse(const Ice::AMD_Object_ice_invokePtr& cb, PyObjec PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); throw Ice::MarshalException(__FILE__, __LINE__); } - _returnType->type->marshal(res, os, &objectMap); + _returnType->type->marshal(res, os, &objectMap, &_metaData); } if(_returnsClasses) @@ -1072,7 +1068,7 @@ IcePy::OperationI::prepareRequest(const Ice::CommunicatorPtr& communicator, PyOb async ? i + 2 : i + 1, const_cast<char*>(opName.c_str())); return false; } - (*p)->type->marshal(arg, os, &objectMap); + (*p)->type->marshal(arg, os, &objectMap, &(*p)->metaData); } if(_sendsClasses) @@ -1113,12 +1109,12 @@ IcePy::OperationI::unmarshalResults(const vector<Ice::Byte>& bytes, const Ice::C for(ParamInfoList::iterator p = _outParams.begin(); p != _outParams.end(); ++p, ++i) { void* closure = reinterpret_cast<void*>(i); - (*p)->type->unmarshal(is, *p, results.get(), closure); + (*p)->type->unmarshal(is, *p, results.get(), closure, &(*p)->metaData); } if(_returnType) { - _returnType->type->unmarshal(is, _returnType, results.get(), 0); + _returnType->type->unmarshal(is, _returnType, results.get(), 0, &_metaData); } if(_returnsClasses) @@ -1200,6 +1196,42 @@ IcePy::OperationI::checkTwowayOnly(const Ice::ObjectPrx& proxy) const } } +void +IcePy::OperationI::convertParams(PyObject* p, ParamInfoList& params, bool& usesClasses) +{ + usesClasses = false; + int sz = PyTuple_GET_SIZE(p); + for(int i = 0; i < sz; ++i) + { + PyObject* item = PyTuple_GET_ITEM(p, i); + assert(PyTuple_Check(item)); + assert(PyTuple_GET_SIZE(item) == 2); + + ParamInfoPtr param = new ParamInfo; + + // + // metaData + // + PyObject* meta = PyTuple_GET_ITEM(item, 0); + assert(PyTuple_Check(meta)); +#ifndef NDEBUG + bool b = +#endif + tupleToStringSeq(meta, param->metaData); + assert(b); + + // + // type + // + param->type = getType(PyTuple_GET_ITEM(item, 1)); + params.push_back(param); + if(!usesClasses) + { + usesClasses = param->type->usesClasses(); + } + } +} + static PyMethodDef OperationMethods[] = { { STRCAST("invoke"), (PyCFunction)operationInvoke, METH_VARARGS, diff --git a/py/modules/IcePy/Types.cpp b/py/modules/IcePy/Types.cpp index c17af2bdefd..e658cf835b4 100644 --- a/py/modules/IcePy/Types.cpp +++ b/py/modules/IcePy/Types.cpp @@ -15,6 +15,7 @@ #include <Proxy.h> #include <Util.h> #include <IceUtil/InputUtil.h> +#include <IceUtil/ScopedArray.h> #include <Ice/LocalException.h> using namespace std; @@ -372,7 +373,7 @@ IcePy::PrimitiveInfo::validate(PyObject* p) } void -IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*) +IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*) { switch(kind) { @@ -519,7 +520,7 @@ IcePy::PrimitiveInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Objec void IcePy::PrimitiveInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { switch(kind) { @@ -620,7 +621,7 @@ IcePy::EnumInfo::validate(PyObject* val) } void -IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*) +IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*) { assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this. @@ -661,7 +662,7 @@ IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* void IcePy::EnumInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { int val; int count = static_cast<int>(enumerators.size()); @@ -748,7 +749,7 @@ IcePy::StructInfo::usesClasses() } void -IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap) +IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, const Ice::StringSeq*) { assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this. @@ -771,13 +772,13 @@ IcePy::StructInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMa memberName); throw AbortMarshaling(); } - member->type->marshal(attr.get(), os, objectMap); + member->type->marshal(attr.get(), os, objectMap, &member->metaData); } } void IcePy::StructInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { PyObjectHandle args = PyTuple_New(0); PyTypeObject* type = (PyTypeObject*)pythonType.get(); @@ -791,7 +792,7 @@ IcePy::StructInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallb for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q, ++i) { DataMemberPtr member = *q; - member->type->unmarshal(is, member, p.get(), 0); + member->type->unmarshal(is, member, p.get(), 0, &member->metaData); } cb->unmarshaled(p.get(), target, closure); @@ -856,7 +857,8 @@ IcePy::SequenceInfo::usesClasses() } void -IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap) +IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, + const Ice::StringSeq* metaData) { if(p == Py_None) { @@ -898,26 +900,40 @@ IcePy::SequenceInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Object void IcePy::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq* metaData) { + // + // Determine the mapping to use for this sequence. Highest priority is given + // to the metaData argument, otherwise we use the mapping of the sequence + // definition. + // + SequenceMappingPtr sm; + if(metaData) + { + SequenceMapping::Type type; + if(!SequenceMapping::getType(*metaData, type) || type == mapping->type) + { + sm = mapping; + } + else + { + sm = new SequenceMapping(type); + } + } + else + { + sm = mapping; + } + PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType); if(pi) { - unmarshalPrimitiveSequence(pi, is, cb, target, closure); + unmarshalPrimitiveSequence(pi, is, cb, target, closure, sm); return; } Ice::Int sz = is->readSize(); - PyObjectHandle result; - if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST) - { - result = PyList_New(sz); - } - else - { - assert(mapping == SEQ_TUPLE); - result = PyTuple_New(sz); - } + PyObjectHandle result = sm->createContainer(sz); if(result.get() == NULL) { @@ -927,30 +943,13 @@ IcePy::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCal for(Ice::Int i = 0; i < sz; ++i) { void* cl = reinterpret_cast<void*>(i); - elementType->unmarshal(is, this, result.get(), cl); + elementType->unmarshal(is, sm, result.get(), cl); } cb->unmarshaled(result.get(), target, closure); } void -IcePy::SequenceInfo::unmarshaled(PyObject* val, PyObject* target, void* closure) -{ - long i = reinterpret_cast<long>(closure); - if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST) - { - PyList_SET_ITEM(target, i, val); - Py_INCREF(val); // PyList_SET_ITEM steals a reference. - } - else - { - assert(mapping == SEQ_TUPLE); - PyTuple_SET_ITEM(target, i, val); - Py_INCREF(val); // PyTuple_SET_ITEM steals a reference. - } -} - -void IcePy::SequenceInfo::print(PyObject* value, IceUtil::Output& out, PrintObjectHistory* history) { if(!validate(value)) @@ -1001,27 +1000,88 @@ IcePy::SequenceInfo::destroy() void IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObject* p, const Ice::OutputStreamPtr& os) { + // + // For most types, we accept an object that implements the buffer protocol + // (this includes the array.array type). + // + const void* buf = 0; + int sz; + if(PyObject_AsReadBuffer(p, &buf, &sz) == 0) + { + const Ice::Byte* b = reinterpret_cast<const Ice::Byte*>(buf); + switch(pi->kind) + { + case PrimitiveInfo::KindBool: + { + os->writeBoolSeq(reinterpret_cast<const bool*>(b), reinterpret_cast<const bool*>(b + sz)); + break; + } + case PrimitiveInfo::KindByte: + { + os->writeByteSeq(reinterpret_cast<const Ice::Byte*>(b), reinterpret_cast<const Ice::Byte*>(b + sz)); + break; + } + case PrimitiveInfo::KindShort: + { + os->writeShortSeq(reinterpret_cast<const Ice::Short*>(b), reinterpret_cast<const Ice::Short*>(b + sz)); + break; + } + case PrimitiveInfo::KindInt: + { + os->writeIntSeq(reinterpret_cast<const Ice::Int*>(b), reinterpret_cast<const Ice::Int*>(b + sz)); + break; + } + case PrimitiveInfo::KindLong: + { + PyErr_Format(PyExc_ValueError, STRCAST("expected sequence value")); + throw AbortMarshaling(); + } + case PrimitiveInfo::KindFloat: + { + os->writeFloatSeq(reinterpret_cast<const Ice::Float*>(b), reinterpret_cast<const Ice::Float*>(b + sz)); + break; + } + case PrimitiveInfo::KindDouble: + { + os->writeDoubleSeq(reinterpret_cast<const Ice::Double*>(b), + reinterpret_cast<const Ice::Double*>(b + sz)); + break; + } + case PrimitiveInfo::KindString: + { + PyErr_Format(PyExc_ValueError, STRCAST("expected sequence value")); + throw AbortMarshaling(); + } + } + return; + } + + PyErr_Clear(); // PyObject_AsReadBuffer sets an exception on failure. + PyObjectHandle fs; - if(pi->kind == PrimitiveInfo::KindByte) + if(!buf) { - // - // Accept a string or a sequence for sequence<byte>. - // - if(!PyString_Check(p)) + if(pi->kind == PrimitiveInfo::KindByte) { - fs = PySequence_Fast(p, STRCAST("expected a string or a sequence value")); - if(fs.get() == NULL) + // + // Accept a string or a sequence for sequence<byte>. + // + if(!PyString_Check(p)) { - return; + fs = PySequence_Fast(p, STRCAST("expected a string, sequence, or buffer value")); + if(fs.get() == NULL) + { + return; + } } } - } - else - { - fs = PySequence_Fast(p, STRCAST("expected a sequence value")); - if(fs.get() == NULL) + else { - return; + fs = PySequence_Fast(p, STRCAST("expected a sequence or buffer value")); + if(fs.get() == NULL) + { + return; + } } } @@ -1029,7 +1089,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje { case PrimitiveInfo::KindBool: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::BoolSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1055,12 +1115,12 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje { assert(PyString_Check(p)); const char* str = PyString_AS_STRING(p); - int sz = PyString_GET_SIZE(p); + sz = PyString_GET_SIZE(p); os->writeByteSeq(reinterpret_cast<const Ice::Byte*>(str), reinterpret_cast<const Ice::Byte*>(str + sz)); } else { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::ByteSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1093,7 +1153,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindShort: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::ShortSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1125,7 +1185,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindInt: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::IntSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1162,7 +1222,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindLong: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::LongSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1199,7 +1259,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindFloat: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::FloatSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1227,7 +1287,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindDouble: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::DoubleSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1255,7 +1315,7 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje } case PrimitiveInfo::KindString: { - int sz = PySequence_Fast_GET_SIZE(fs.get()); + sz = PySequence_Fast_GET_SIZE(fs.get()); Ice::StringSeq seq(sz); for(int i = 0; i < sz; ++i) { @@ -1286,7 +1346,8 @@ IcePy::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, PyObje void IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, const Ice::InputStreamPtr& is, - const UnmarshalCallbackPtr& cb, PyObject* target, void* closure) + const UnmarshalCallbackPtr& cb, PyObject* target, void* closure, + const SequenceMappingPtr& sm) { PyObjectHandle result; @@ -1294,9 +1355,10 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons { case PrimitiveInfo::KindBool: { - Ice::BoolSeq seq = is->readBoolSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const bool*, const bool*> p; + IceUtil::ScopedArray<bool> arr(is->readBoolSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1304,7 +1366,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - setItem(result.get(), i, seq[i] ? Py_True : Py_False); + sm->setItem(result.get(), i, p.first[i] ? Py_True : Py_False); } break; } @@ -1313,7 +1375,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons pair<const Ice::Byte*, const Ice::Byte*> p; is->readByteSeq(p); int sz = static_cast<int>(p.second - p.first); - if(mapping == SEQ_DEFAULT) + if(sm->type == SequenceMapping::SEQ_DEFAULT) { result = PyString_FromStringAndSize(reinterpret_cast<const char*>(p.first), sz); if(result.get() == NULL) @@ -1323,7 +1385,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons } else { - result = createContainer(sz); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1336,16 +1398,17 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } } break; } case PrimitiveInfo::KindShort: { - Ice::ShortSeq seq = is->readShortSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const Ice::Short*, const Ice::Short*> p; + IceUtil::ScopedArray<Ice::Short> arr(is->readShortSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1353,20 +1416,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - PyObjectHandle item = PyInt_FromLong(seq[i]); + PyObjectHandle item = PyInt_FromLong(p.first[i]); if(item.get() == NULL) { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } case PrimitiveInfo::KindInt: { - Ice::IntSeq seq = is->readIntSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const Ice::Int*, const Ice::Int*> p; + IceUtil::ScopedArray<Ice::Int> arr(is->readIntSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1374,20 +1438,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - PyObjectHandle item = PyInt_FromLong(seq[i]); + PyObjectHandle item = PyInt_FromLong(p.first[i]); if(item.get() == NULL) { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } case PrimitiveInfo::KindLong: { - Ice::LongSeq seq = is->readLongSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const Ice::Long*, const Ice::Long*> p; + IceUtil::ScopedArray<Ice::Long> arr(is->readLongSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1395,20 +1460,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - PyObjectHandle item = PyLong_FromLongLong(seq[i]); + PyObjectHandle item = PyLong_FromLongLong(p.first[i]); if(item.get() == NULL) { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } case PrimitiveInfo::KindFloat: { - Ice::FloatSeq seq = is->readFloatSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const Ice::Float*, const Ice::Float*> p; + IceUtil::ScopedArray<Ice::Float> arr(is->readFloatSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1416,20 +1482,21 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - PyObjectHandle item = PyFloat_FromDouble(seq[i]); + PyObjectHandle item = PyFloat_FromDouble(p.first[i]); if(item.get() == NULL) { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } case PrimitiveInfo::KindDouble: { - Ice::DoubleSeq seq = is->readDoubleSeq(); - int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + pair<const Ice::Double*, const Ice::Double*> p; + IceUtil::ScopedArray<Ice::Double> arr(is->readDoubleSeq(p)); + int sz = static_cast<int>(p.second - p.first); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1437,12 +1504,12 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons for(int i = 0; i < sz; ++i) { - PyObjectHandle item = PyFloat_FromDouble(seq[i]); + PyObjectHandle item = PyFloat_FromDouble(p.first[i]); if(item.get() == NULL) { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } @@ -1450,7 +1517,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons { Ice::StringSeq seq = is->readStringSeq(); int sz = static_cast<int>(seq.size()); - result = createContainer(sz); + result = sm->createContainer(sz); if(result.get() == NULL) { throw AbortMarshaling(); @@ -1463,7 +1530,7 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons { throw AbortMarshaling(); } - setItem(result.get(), i, item.get()); + sm->setItem(result.get(), i, item.get()); } break; } @@ -1471,31 +1538,89 @@ IcePy::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, cons cb->unmarshaled(result.get(), target, closure); } +bool +IcePy::SequenceInfo::SequenceMapping::getType(const Ice::StringSeq& metaData, Type& t) +{ + if(!metaData.empty()) + { + for(Ice::StringSeq::const_iterator p = metaData.begin(); p != metaData.end(); ++p) + { + if((*p) == "python:seq:default") + { + t = SEQ_DEFAULT; + return true; + } + else if((*p) == "python:seq:tuple") + { + t = SEQ_TUPLE; + return true; + } + else if((*p) == "python:seq:list") + { + t = SEQ_LIST; + return true; + } + } + } + + return false; +} + +IcePy::SequenceInfo::SequenceMapping::SequenceMapping(Type t) : + type(t) +{ +} + +IcePy::SequenceInfo::SequenceMapping::SequenceMapping(const Ice::StringSeq& meta) +{ + if(!getType(meta, type)) + { + type = SEQ_DEFAULT; + } +} + +void +IcePy::SequenceInfo::SequenceMapping::unmarshaled(PyObject* val, PyObject* target, void* closure) +{ + long i = reinterpret_cast<long>(closure); + if(type == SEQ_DEFAULT || type == SEQ_LIST) + { + PyList_SET_ITEM(target, i, val); + Py_INCREF(val); // PyList_SET_ITEM steals a reference. + } + else + { + assert(type == SEQ_TUPLE); + PyTuple_SET_ITEM(target, i, val); + Py_INCREF(val); // PyTuple_SET_ITEM steals a reference. + } +} + PyObject* -IcePy::SequenceInfo::createContainer(int sz) const +IcePy::SequenceInfo::SequenceMapping::createContainer(int sz) const { - if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST) + if(type == SEQ_DEFAULT || type == SEQ_LIST) { return PyList_New(sz); } else { - assert(mapping == SEQ_TUPLE); + assert(type == SEQ_TUPLE); return PyTuple_New(sz); } } void -IcePy::SequenceInfo::setItem(PyObject* cont, int i, PyObject* val) const +IcePy::SequenceInfo::SequenceMapping::setItem(PyObject* cont, int i, PyObject* val) const { - if(mapping == SEQ_DEFAULT || mapping == SEQ_LIST) + if(type == SEQ_DEFAULT || type == SEQ_LIST) { Py_INCREF(val); PyList_SET_ITEM(cont, i, val); // PyList_SET_ITEM steals a reference. } else { - assert(mapping == SEQ_TUPLE); + assert(type == SEQ_TUPLE); Py_INCREF(val); PyTuple_SET_ITEM(cont, i, val); // PyTuple_SET_ITEM steals a reference. } @@ -1523,7 +1648,8 @@ IcePy::DictionaryInfo::usesClasses() } void -IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap) +IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, + const Ice::StringSeq*) { if(p == Py_None) { @@ -1562,7 +1688,7 @@ IcePy::DictionaryInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Obje void IcePy::DictionaryInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { PyObjectHandle p = PyDict_New(); if(p.get() == NULL) @@ -1697,7 +1823,8 @@ IcePy::ClassInfo::usesClasses() } void -IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap) +IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, + const Ice::StringSeq*) { if(pythonType.get() == NULL) { @@ -1751,7 +1878,7 @@ IcePy::ClassInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap void IcePy::ClassInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { if(pythonType.get() == NULL) { @@ -1856,7 +1983,7 @@ IcePy::ProxyInfo::validate(PyObject* val) } void -IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*) +IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, const Ice::StringSeq*) { if(p == Py_None) { @@ -1874,7 +2001,7 @@ IcePy::ProxyInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap void IcePy::ProxyInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, - void* closure) + void* closure, const Ice::StringSeq*) { Ice::ObjectPrx proxy = is->readProxy(); @@ -1982,7 +2109,7 @@ IcePy::ObjectWriter::write(const Ice::OutputStreamPtr& os) const throw AbortMarshaling(); } - member->type->marshal(val.get(), os, _map); + member->type->marshal(val.get(), os, _map, &member->metaData); } os->endSlice(); @@ -2045,7 +2172,7 @@ IcePy::ObjectReader::read(const Ice::InputStreamPtr& is, bool rid) for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p) { DataMemberPtr member = *p; - member->type->unmarshal(is, member, _object, 0); + member->type->unmarshal(is, member, _object, 0, &member->metaData); } is->endSlice(); @@ -2190,7 +2317,7 @@ IcePy::ExceptionInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, Objec throw AbortMarshaling(); } - member->type->marshal(val.get(), os, objectMap); + member->type->marshal(val.get(), os, objectMap, &member->metaData); } os->endSlice(); @@ -2213,7 +2340,7 @@ IcePy::ExceptionInfo::unmarshal(const Ice::InputStreamPtr& is) for(DataMemberList::iterator q = info->members.begin(); q != info->members.end(); ++q) { DataMemberPtr member = *q; - member->type->unmarshal(is, member, p.get(), 0); + member->type->unmarshal(is, member, p.get(), 0, &member->metaData); } is->endSlice(); @@ -2539,13 +2666,15 @@ IcePy_defineEnum(PyObject*, PyObject* args) { char* id; PyObject* type; + PyObject* meta; PyObject* enumerators; - if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &type, &enumerators)) + if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &meta, &enumerators)) { return NULL; } assert(PyType_Check(type)); + assert(PyTuple_Check(meta)); assert(PyTuple_Check(enumerators)); EnumInfoPtr info = new EnumInfo; @@ -2565,19 +2694,49 @@ IcePy_defineEnum(PyObject*, PyObject* args) return createType(info); } +static void +convertDataMembers(PyObject* members, DataMemberList& l) +{ + int sz = PyTuple_GET_SIZE(members); + for(int i = 0; i < sz; ++i) + { + PyObject* m = PyTuple_GET_ITEM(members, i); + assert(PyTuple_Check(m)); + assert(PyTuple_GET_SIZE(m) == 3); + + PyObject* name = PyTuple_GET_ITEM(m, 0); // Member name. + assert(PyString_Check(name)); + PyObject* meta = PyTuple_GET_ITEM(m, 1); // Member metadata. + assert(PyTuple_Check(meta)); + PyObject* t = PyTuple_GET_ITEM(m, 2); // Member type. + + DataMemberPtr member = new DataMember; + member->name = string(PyString_AS_STRING(name), PyString_GET_SIZE(name)); +#ifndef NDEBUG + bool b = +#endif + tupleToStringSeq(meta, member->metaData); + assert(b); + member->type = getType(t); + l.push_back(member); + } +} + extern "C" PyObject* IcePy_defineStruct(PyObject*, PyObject* args) { char* id; PyObject* type; + PyObject* meta; PyObject* members; - if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &type, &members)) + if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &meta, &members)) { return NULL; } assert(PyType_Check(type)); + assert(PyTuple_Check(meta)); assert(PyTuple_Check(members)); StructInfoPtr info = new StructInfo; @@ -2585,20 +2744,7 @@ IcePy_defineStruct(PyObject*, PyObject* args) info->pythonType = type; Py_INCREF(type); - int sz = PyTuple_GET_SIZE(members); - for(int i = 0; i < sz; ++i) - { - PyObject* m = PyTuple_GET_ITEM(members, i); - assert(PyTuple_Check(m)); - assert(PyTuple_GET_SIZE(m) == 2); - PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name. - assert(PyString_Check(s)); - PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type. - DataMemberPtr member = new DataMember; - member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s)); - member->type = getType(t); - info->members.push_back(member); - } + convertDataMembers(members, info->members); return createType(info); } @@ -2608,30 +2754,25 @@ PyObject* IcePy_defineSequence(PyObject*, PyObject* args) { char* id; - int mapping; + PyObject* meta; PyObject* elementType; - if(!PyArg_ParseTuple(args, STRCAST("siO"), &id, &mapping, &elementType)) + if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &meta, &elementType)) { return NULL; } + assert(PyTuple_Check(meta)); + + vector<string> metaData; +#ifndef NDEBUG + bool b = +#endif + tupleToStringSeq(meta, metaData); + assert(b); + SequenceInfoPtr info = new SequenceInfo; info->id = id; - switch(mapping) - { - case 0: - info->mapping = SequenceInfo::SEQ_DEFAULT; - break; - case 1: - info->mapping = SequenceInfo::SEQ_TUPLE; - break; - case 2: - info->mapping = SequenceInfo::SEQ_LIST; - break; - default: - assert(false); - break; - } + info->mapping = new SequenceInfo::SequenceMapping(metaData); info->elementType = getType(elementType); return createType(info); @@ -2642,13 +2783,16 @@ PyObject* IcePy_defineDictionary(PyObject*, PyObject* args) { char* id; + PyObject* meta; PyObject* keyType; PyObject* valueType; - if(!PyArg_ParseTuple(args, STRCAST("sOO"), &id, &keyType, &valueType)) + if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &meta, &keyType, &valueType)) { return NULL; } + assert(PyTuple_Check(meta)); + DictionaryInfoPtr info = new DictionaryInfo; info->id = id; info->keyType = getType(keyType); @@ -2745,16 +2889,18 @@ IcePy_defineClass(PyObject*, PyObject* args) { char* id; PyObject* type; + PyObject* meta; int isAbstract; PyObject* base; PyObject* interfaces; PyObject* members; - if(!PyArg_ParseTuple(args, STRCAST("sOiOOO"), &id, &type, &isAbstract, &base, &interfaces, &members)) + if(!PyArg_ParseTuple(args, STRCAST("sOOiOOO"), &id, &type, &meta, &isAbstract, &base, &interfaces, &members)) { return NULL; } assert(PyType_Check(type)); + assert(PyTuple_Check(meta)); assert(PyTuple_Check(interfaces)); assert(PyTuple_Check(members)); @@ -2790,20 +2936,7 @@ IcePy_defineClass(PyObject*, PyObject* args) info->interfaces.push_back(iface); } - sz = PyTuple_GET_SIZE(members); - for(i = 0; i < sz; ++i) - { - PyObject* m = PyTuple_GET_ITEM(members, i); - assert(PyTuple_Check(m)); - assert(PyTuple_GET_SIZE(m) == 2); - PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name. - assert(PyString_Check(s)); - PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type. - DataMemberPtr member = new DataMember; - member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s)); - member->type = getType(t); - info->members.push_back(member); - } + convertDataMembers(members, info->members); info->pythonType = type; Py_INCREF(type); @@ -2820,14 +2953,16 @@ IcePy_defineException(PyObject*, PyObject* args) { char* id; PyObject* type; + PyObject* meta; PyObject* base; PyObject* members; - if(!PyArg_ParseTuple(args, STRCAST("sOOO"), &id, &type, &base, &members)) + if(!PyArg_ParseTuple(args, STRCAST("sOOOO"), &id, &type, &meta, &base, &members)) { return NULL; } assert(PyClass_Check(type)); + assert(PyTuple_Check(meta)); assert(PyTuple_Check(members)); ExceptionInfoPtr info = new ExceptionInfo; @@ -2841,22 +2976,13 @@ IcePy_defineException(PyObject*, PyObject* args) info->usesClasses = false; - int sz = PyTuple_GET_SIZE(members); - for(int i = 0; i < sz; ++i) + convertDataMembers(members, info->members); + + for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p) { - PyObject* m = PyTuple_GET_ITEM(members, i); - assert(PyTuple_Check(m)); - assert(PyTuple_GET_SIZE(m) == 2); - PyObject* s = PyTuple_GET_ITEM(m, 0); // Member name. - assert(PyString_Check(s)); - PyObject* t = PyTuple_GET_ITEM(m, 1); // Member type. - DataMemberPtr member = new DataMember; - member->name = string(PyString_AS_STRING(s), PyString_GET_SIZE(s)); - member->type = getType(t); - info->members.push_back(member); if(!info->usesClasses) { - info->usesClasses = member->type->usesClasses(); + info->usesClasses = (*p)->type->usesClasses(); } } diff --git a/py/modules/IcePy/Types.h b/py/modules/IcePy/Types.h index cd1834e1b3c..c710f1f304f 100644 --- a/py/modules/IcePy/Types.h +++ b/py/modules/IcePy/Types.h @@ -91,8 +91,9 @@ public: // The marshal and unmarshal functions can raise Ice exceptions, and may raise // AbortMarshaling if an error occurs. // - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*) = 0; - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*) = 0; + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0) = 0; + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0) = 0; virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*) = 0; }; @@ -109,8 +110,9 @@ public: virtual bool validate(PyObject*); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); @@ -143,8 +145,9 @@ public: virtual bool validate(PyObject*); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); @@ -161,6 +164,7 @@ public: virtual void unmarshaled(PyObject*, PyObject*, void*); std::string name; + std::vector<std::string> metaData; TypeInfoPtr type; }; typedef IceUtil::Handle<DataMember> DataMemberPtr; @@ -179,8 +183,9 @@ public: virtual bool usesClasses(); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); @@ -205,28 +210,41 @@ public: virtual bool usesClasses(); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); - virtual void unmarshaled(PyObject*, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); virtual void destroy(); - void marshalPrimitiveSequence(const PrimitiveInfoPtr&, PyObject*, const Ice::OutputStreamPtr&); - void unmarshalPrimitiveSequence(const PrimitiveInfoPtr&, const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, - PyObject*, void*); + struct SequenceMapping : public UnmarshalCallback + { + enum Type { SEQ_DEFAULT, SEQ_TUPLE, SEQ_LIST }; + + SequenceMapping(Type); + SequenceMapping(const Ice::StringSeq&); + + static bool getType(const Ice::StringSeq&, Type&); - enum Mapping { SEQ_DEFAULT, SEQ_TUPLE, SEQ_LIST }; + virtual void unmarshaled(PyObject*, PyObject*, void*); + + PyObject* createContainer(int) const; + void setItem(PyObject*, int, PyObject*) const; + + Type type; + }; + typedef IceUtil::Handle<SequenceMapping> SequenceMappingPtr; std::string id; - Mapping mapping; + SequenceMappingPtr mapping; TypeInfoPtr elementType; private: - PyObject* createContainer(int) const; - void setItem(PyObject*, int, PyObject*) const; + void marshalPrimitiveSequence(const PrimitiveInfoPtr&, PyObject*, const Ice::OutputStreamPtr&); + void unmarshalPrimitiveSequence(const PrimitiveInfoPtr&, const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, + PyObject*, void*, const SequenceMappingPtr&); }; typedef IceUtil::Handle<SequenceInfo> SequenceInfoPtr; @@ -243,8 +261,9 @@ public: virtual bool usesClasses(); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void unmarshaled(PyObject*, PyObject*, void*); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); @@ -279,8 +298,9 @@ public: virtual bool usesClasses(); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); @@ -309,8 +329,9 @@ public: virtual bool validate(PyObject*); - virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*); - virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*); + virtual void marshal(PyObject*, const Ice::OutputStreamPtr&, ObjectMap*, const Ice::StringSeq* = 0); + virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, PyObject*, void*, + const Ice::StringSeq* = 0); virtual void print(PyObject*, IceUtil::Output&, PrintObjectHistory*); diff --git a/py/modules/IcePy/Util.cpp b/py/modules/IcePy/Util.cpp index ee5d4660970..6330f1ee95b 100644 --- a/py/modules/IcePy/Util.cpp +++ b/py/modules/IcePy/Util.cpp @@ -310,20 +310,19 @@ IcePy::listToStringSeq(PyObject* l, Ice::StringSeq& seq) { assert(PyList_Check(l)); - int sz = PyList_Size(l); + int sz = PyList_GET_SIZE(l); for(int i = 0; i < sz; ++i) { - PyObject* item = PyList_GetItem(l, i); - if(item == NULL) - { - return false; - } - char* str = PyString_AsString(item); - if(str == NULL) - { - return false; - } - seq.push_back(str); + PyObject* item = PyList_GET_ITEM(l, i); + if(item == NULL) + { + return false; + } + if(!PyString_Check(item)) + { + return false; + } + seq.push_back(string(PyString_AS_STRING(item), PyString_GET_SIZE(item))); } return true; @@ -355,6 +354,29 @@ IcePy::stringSeqToList(const Ice::StringSeq& seq, PyObject* l) } bool +IcePy::tupleToStringSeq(PyObject* t, Ice::StringSeq& seq) +{ + assert(PyTuple_Check(t)); + + int sz = PyTuple_GET_SIZE(t); + for(int i = 0; i < sz; ++i) + { + PyObject* item = PyTuple_GET_ITEM(t, i); + if(item == NULL) + { + return false; + } + if(!PyString_Check(item)) + { + return false; + } + seq.push_back(string(PyString_AS_STRING(item), PyString_GET_SIZE(item))); + } + + return true; +} + +bool IcePy::dictionaryToContext(PyObject* dict, Ice::Context& context) { assert(PyDict_Check(dict)); diff --git a/py/modules/IcePy/Util.h b/py/modules/IcePy/Util.h index fc33a8ca62f..64051b717d6 100644 --- a/py/modules/IcePy/Util.h +++ b/py/modules/IcePy/Util.h @@ -114,6 +114,11 @@ bool listToStringSeq(PyObject*, Ice::StringSeq&); bool stringSeqToList(const Ice::StringSeq&, PyObject*); // +// Convert a tuple to Ice::StringSeq. +// +bool tupleToStringSeq(PyObject*, Ice::StringSeq&); + +// // Convert Ice::Context to and from a Python dictionary. // bool dictionaryToContext(PyObject*, Ice::Context&); diff --git a/py/python/Ice.py b/py/python/Ice.py index 1fc0f3713f1..608fc52d177 100644 --- a/py/python/Ice.py +++ b/py/python/Ice.py @@ -691,16 +691,16 @@ class Application(object): # # Define Ice::Object and Ice::ObjectPrx. # -IcePy._t_Object = IcePy.defineClass('::Ice::Object', Object, False, None, (), ()) +IcePy._t_Object = IcePy.defineClass('::Ice::Object', Object, (), False, None, (), ()) IcePy._t_ObjectPrx = IcePy.defineProxy('::Ice::Object', ObjectPrx) Object.ice_type = IcePy._t_Object -Object._op_ice_isA = IcePy.Operation('ice_isA', OperationMode.Idempotent, OperationMode.Nonmutating, False, (IcePy._t_string,), (), IcePy._t_bool, ()) -Object._op_ice_ping = IcePy.Operation('ice_ping', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), None, ()) -Object._op_ice_ids = IcePy.Operation('ice_ids', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), _t_StringSeq, ()) -Object._op_ice_id = IcePy.Operation('ice_id', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), IcePy._t_string, ()) +Object._op_ice_isA = IcePy.Operation('ice_isA', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (((), IcePy._t_string),), (), IcePy._t_bool, ()) +Object._op_ice_ping = IcePy.Operation('ice_ping', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), None, ()) +Object._op_ice_ids = IcePy.Operation('ice_ids', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), _t_StringSeq, ()) +Object._op_ice_id = IcePy.Operation('ice_id', OperationMode.Idempotent, OperationMode.Nonmutating, False, (), (), (), IcePy._t_string, ()) -IcePy._t_LocalObject = IcePy.defineClass('::Ice::LocalObject', LocalObject, False, None, (), ()) +IcePy._t_LocalObject = IcePy.defineClass('::Ice::LocalObject', LocalObject, (), False, None, (), ()) LocalObject.ice_type = IcePy._t_LocalObject # diff --git a/py/test/Ice/custom/AllTests.py b/py/test/Ice/custom/AllTests.py new file mode 100644 index 00000000000..450453e2d92 --- /dev/null +++ b/py/test/Ice/custom/AllTests.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import sys, string, re, traceback, Ice, Test + +def test(b): + if not b: + raise RuntimeError('test assertion failed') + +def allTests(communicator): + ref = "test:default -p 12010 -t 10000" + base = communicator.stringToProxy(ref) + test(base) + + custom = Test.CustomPrx.checkedCast(base) + test(custom) + + byteList = [1, 2, 3, 4, 5] + byteString = ''.join(map(chr, byteList)) + stringList = ['s1', 's2', 's3'] + + print "testing custom sequences...", + + (r, b2) = custom.opByteString1(byteString) + test(isinstance(r, str)) + test(isinstance(b2, str)) + test(r == byteString) + test(b2 == byteString) + + (r, b2) = custom.opByteString2(byteString) + test(isinstance(r, tuple)) + test(isinstance(b2, list)) + for i in range(0, len(byteList)): + test(r[i] == byteList[i]) + test(b2[i] == byteList[i]) + + (r, b2) = custom.opByteList1(byteList) + test(isinstance(r, list)) + test(isinstance(b2, list)) + for i in range(0, len(byteList)): + test(r[i] == byteList[i]) + test(b2[i] == byteList[i]) + + (r, b2) = custom.opByteList2(byteList) + test(isinstance(r, str)) + test(isinstance(b2, tuple)) + test(r == byteString) + for i in range(0, len(byteList)): + test(b2[i] == byteList[i]) + + (r, b2) = custom.opStringList1(stringList) + test(isinstance(r, list)) + test(isinstance(b2, list)) + test(r == stringList) + test(b2 == stringList) + + (r, b2) = custom.opStringList2(stringList) + test(isinstance(r, tuple)) + test(isinstance(b2, tuple)) + for i in range(0, len(stringList)): + test(r[i] == stringList[i]) + test(b2[i] == stringList[i]) + + (r, b2) = custom.opStringTuple1(stringList) + test(isinstance(r, tuple)) + test(isinstance(b2, tuple)) + for i in range(0, len(stringList)): + test(r[i] == stringList[i]) + test(b2[i] == stringList[i]) + + (r, b2) = custom.opStringTuple2(stringList) + test(isinstance(r, list)) + test(isinstance(b2, list)) + test(r == stringList) + test(b2 == stringList) + + s = Test.S() + s.b1 = byteList; + s.b2 = byteList; + s.b3 = byteList; + s.b4 = byteList; + s.s1 = stringList; + s.s2 = stringList; + s.s3 = stringList; + s.s4 = stringList; + custom.sendS(s) + + c = Test.C() + c.b1 = byteList; + c.b2 = byteList; + c.b3 = byteList; + c.b4 = byteList; + c.s1 = stringList; + c.s2 = stringList; + c.s3 = stringList; + c.s4 = stringList; + custom.sendC(c) + + print "ok" + + return custom diff --git a/py/test/Ice/custom/Client.py b/py/test/Ice/custom/Client.py new file mode 100644 index 00000000000..4831b78c28d --- /dev/null +++ b/py/test/Ice/custom/Client.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import os, sys, traceback + +for toplevel in [".", "..", "../..", "../../..", "../../../.."]: + toplevel = os.path.normpath(toplevel) + if os.path.exists(os.path.join(toplevel, "python", "Ice.py")): + break +else: + raise "can't find toplevel directory!" + +sys.path.insert(0, os.path.join(toplevel, "python")) +sys.path.insert(0, os.path.join(toplevel, "lib")) + +import Ice +Ice.loadSlice('Test.ice') +import Test, AllTests + +def run(args, communicator): + custom = AllTests.allTests(communicator) + custom.shutdown() + return True + +try: + communicator = Ice.initialize(sys.argv) + status = run(sys.argv, communicator) +except: + traceback.print_exc() + status = False + +if communicator: + try: + communicator.destroy() + except: + traceback.print_exc() + status = False + +sys.exit(not status) diff --git a/py/test/Ice/custom/Server.py b/py/test/Ice/custom/Server.py new file mode 100644 index 00000000000..9282c34333a --- /dev/null +++ b/py/test/Ice/custom/Server.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import os, sys, traceback + +for toplevel in [".", "..", "../..", "../../..", "../../../.."]: + toplevel = os.path.normpath(toplevel) + if os.path.exists(os.path.join(toplevel, "python", "Ice.py")): + break +else: + raise "can't find toplevel directory!" + +sys.path.insert(0, os.path.join(toplevel, "python")) +sys.path.insert(0, os.path.join(toplevel, "lib")) + +import Ice +Ice.loadSlice('Test.ice') +import Test + +def test(b): + if not b: + raise RuntimeError('test assertion failed') + +class CustomI(Test.Custom): + def __init__(self, adapter): + self._adapter = adapter + + def opByteString1(self, b1, current=None): + test(isinstance(b1, str)) + return (b1, b1) + + def opByteString2(self, b1, current=None): + test(isinstance(b1, list)) + return (b1, b1) + + def opByteList1(self, b1, current=None): + test(isinstance(b1, list)) + return (b1, b1) + + def opByteList2(self, b1, current=None): + test(isinstance(b1, tuple)) + return (b1, b1) + + def opStringList1(self, s1, current=None): + test(isinstance(s1, list)) + return (s1, s1) + + def opStringList2(self, s1, current=None): + test(isinstance(s1, tuple)) + return (s1, s1) + + def opStringTuple1(self, s1, current=None): + test(isinstance(s1, tuple)) + return (s1, s1) + + def opStringTuple2(self, s1, current=None): + test(isinstance(s1, list)) + return (s1, s1) + + def sendS(self, val, current=None): + test(isinstance(val.b1, str)) + test(isinstance(val.b2, list)) + test(isinstance(val.b3, str)) + test(isinstance(val.b4, list)) + test(isinstance(val.s1, list)) + test(isinstance(val.s2, tuple)) + test(isinstance(val.s3, tuple)) + test(isinstance(val.s4, list)) + + def sendC(self, val, current=None): + test(isinstance(val.b1, str)) + test(isinstance(val.b2, list)) + test(isinstance(val.b3, str)) + test(isinstance(val.b4, list)) + test(isinstance(val.s1, list)) + test(isinstance(val.s2, tuple)) + test(isinstance(val.s3, tuple)) + test(isinstance(val.s4, list)) + + def shutdown(self, current=None): + self._adapter.getCommunicator().shutdown() + +def run(args, communicator): + communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010 -t 10000") + adapter = communicator.createObjectAdapter("TestAdapter") + object = CustomI(adapter) + adapter.add(object, communicator.stringToIdentity("test")) + adapter.activate() + communicator.waitForShutdown() + return True + +try: + communicator = Ice.initialize(sys.argv) + status = run(sys.argv, communicator) +except: + traceback.print_exc() + status = False + +if communicator: + try: + communicator.destroy() + except: + traceback.print_exc() + status = False + +sys.exit(not status) diff --git a/py/test/Ice/custom/Test.ice b/py/test/Ice/custom/Test.ice new file mode 100644 index 00000000000..d142530c206 --- /dev/null +++ b/py/test/Ice/custom/Test.ice @@ -0,0 +1,70 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef TEST_ICE +#define TEST_ICE + +module Test +{ + sequence<byte> ByteString; // By default, sequence<byte> is received as a string. + ["python:seq:list"] sequence<byte> ByteList; + + sequence<string> StringList; // By default, a sequence is received as a list. + ["python:seq:tuple"] sequence<string> StringTuple; + + struct S + { + ByteString b1; + ["python:seq:list"] ByteString b2; + ["python:seq:default"] ByteList b3; + ByteList b4; + StringList s1; + ["python:seq:tuple"] StringList s2; + StringTuple s3; + ["python:seq:default"] StringTuple s4; + }; + + class C + { + ByteString b1; + ["python:seq:list"] ByteString b2; + ["python:seq:default"] ByteList b3; + ByteList b4; + StringList s1; + ["python:seq:tuple"] StringList s2; + StringTuple s3; + ["python:seq:default"] StringTuple s4; + }; + + interface Custom + { + ByteString opByteString1(ByteString b1, out ByteString b2); + ["python:seq:tuple"] ByteString opByteString2(["python:seq:list"] ByteString b1, + out ["python:seq:list"] ByteString b2); + + ByteList opByteList1(ByteList b1, out ByteList b2); + ["python:seq:default"] ByteList opByteList2(["python:seq:tuple"] ByteList b1, + out ["python:seq:tuple"] ByteList b2); + + StringList opStringList1(StringList s1, out StringList s2); + ["python:seq:tuple"] StringList opStringList2(["python:seq:tuple"] StringList s1, + out ["python:seq:tuple"] StringList s2); + + StringTuple opStringTuple1(StringTuple s1, out StringTuple s2); + ["python:seq:list"] StringTuple opStringTuple2(["python:seq:list"] StringTuple s1, + out ["python:seq:default"] StringTuple s2); + + void sendS(S val); + void sendC(C val); + + void shutdown(); + }; +}; + +#endif diff --git a/py/test/Ice/custom/run.py b/py/test/Ice/custom/run.py new file mode 100755 index 00000000000..1bb1ba86d1b --- /dev/null +++ b/py/test/Ice/custom/run.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import os, sys + +for toplevel in [".", "..", "../..", "../../..", "../../../.."]: + toplevel = os.path.normpath(toplevel) + if os.path.exists(os.path.join(toplevel, "config", "TestUtil.py")): + break +else: + raise "can't find toplevel directory!" + +sys.path.append(os.path.join(toplevel, "config")) +import TestUtil + +name = os.path.join("Ice", "custom") + +TestUtil.clientServerTest(name) +sys.exit(0) diff --git a/py/test/Ice/operations/Twoways.py b/py/test/Ice/operations/Twoways.py index f7f784938f5..dcf925df4dc 100644 --- a/py/test/Ice/operations/Twoways.py +++ b/py/test/Ice/operations/Twoways.py @@ -8,7 +8,7 @@ # # ********************************************************************** -import Ice, math, Test +import Ice, math, Test, array def test(b): if not b: @@ -147,6 +147,31 @@ def twoways(communicator, initData, p): test(rso[7] == '\xf4') # + # opByteS (array) + # + print "array", + bsi1 = array.array('B') + bsi1.fromlist([0x01, 0x11, 0x12, 0x22]) + bsi2 = array.array('B') + bsi2.fromlist([0xf1, 0xf2, 0xf3, 0xf4]) + + rso, bso = p.opByteS(bsi1, bsi2) + test(len(bso) == 4) + test(bso[0] == '\x22') + test(bso[1] == '\x12') + test(bso[2] == '\x11') + test(bso[3] == '\x01') + test(len(rso) == 8) + test(rso[0] == '\x01') + test(rso[1] == '\x11') + test(rso[2] == '\x12') + test(rso[3] == '\x22') + test(rso[4] == '\xf1') + test(rso[5] == '\xf2') + test(rso[6] == '\xf3') + test(rso[7] == '\xf4') + + # # opBoolS # bsi1 = (True, True, False) @@ -164,6 +189,25 @@ def twoways(communicator, initData, p): test(rso[2]) # + # opBoolS (array) + # + bsi1 = array.array('B') + bsi1.fromlist([1, 1, 0]) + bsi2 = array.array('B') + bsi2.fromlist([0]) + + rso, bso = p.opBoolS(bsi1, bsi2) + test(len(bso) == 4) + test(bso[0]) + test(bso[1]) + test(not bso[2]) + test(not bso[3]) + test(len(rso) == 3) + test(not rso[0]) + test(rso[1]) + test(rso[2]) + + # # opShortIntLongS # ssi = (1, 2, 3) @@ -193,6 +237,37 @@ def twoways(communicator, initData, p): test(rso[2] == 20) # + # opShortIntLongS (array) + # + ssi = array.array('h') + ssi.fromlist([1, 2, 3]) + isi = array.array('i') + isi.fromlist([5, 6, 7, 8]) + lsi = (10, 30, 20) # Can't store Ice::Long in an array. + + rso, sso, iso, lso = p.opShortIntLongS(ssi, isi, lsi) + test(len(sso) == 3) + test(sso[0] == 1) + test(sso[1] == 2) + test(sso[2] == 3) + test(len(iso) == 4) + test(iso[0] == 8) + test(iso[1] == 7) + test(iso[2] == 6) + test(iso[3] == 5) + test(len(lso) == 6) + test(lso[0] == 10) + test(lso[1] == 30) + test(lso[2] == 20) + test(lso[3] == 10) + test(lso[4] == 30) + test(lso[5] == 20) + test(len(rso) == 3) + test(rso[0] == 10) + test(rso[1] == 30) + test(rso[2] == 20) + + # # opFloatDoubleS # fsi = (3.14, 1.11) @@ -214,6 +289,29 @@ def twoways(communicator, initData, p): test(rso[4] - 1.11 < 0.001) # + # opFloatDoubleS (array) + # + fsi = array.array('f') + fsi.fromlist([3.14, 1.11]) + dsi = array.array('d') + dsi.fromlist([1.1E10, 1.2E10, 1.3E10]) + + rso, fso, dso = p.opFloatDoubleS(fsi, dsi) + test(len(fso) == 2) + test(fso[0] - 3.14 < 0.001) + test(fso[1] - 1.11 < 0.001) + test(len(dso) == 3) + test(dso[0] == 1.3E10) + test(dso[1] == 1.2E10) + test(dso[2] == 1.1E10) + test(len(rso) == 5) + test(rso[0] == 1.1E10) + test(rso[1] == 1.2E10) + test(rso[2] == 1.3E10) + test(rso[3] - 3.14 < 0.001) + test(rso[4] - 1.11 < 0.001) + + # # opStringS # ssi1 = ('abc', 'de', 'fghi') |