diff --git a/examples/issues/source/issues.d b/examples/issues/source/issues.d index de598c80..a0376551 100644 --- a/examples/issues/source/issues.d +++ b/examples/issues/source/issues.d @@ -284,3 +284,8 @@ struct MethodWithScopeSafeDelegate { return cb(i, 33.3, Struct()); } } + + +struct Issue268 { + int i; +} diff --git a/examples/phobos/std_datetime/source/app.d b/examples/phobos/std_datetime/source/app.d index 6f546dbf..a94ee264 100644 --- a/examples/phobos/std_datetime/source/app.d +++ b/examples/phobos/std_datetime/source/app.d @@ -15,3 +15,11 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8datetime8timezone13PosixTimeZone6TTInfoZ7_py_cmpUNbPSQDm3raw7_objectQriZQv") +private void hack1() { assert(0); } diff --git a/examples/phobos/std_experimental/source/app.d b/examples/phobos/std_experimental/source/app.d index 1049bac9..6e31c011 100644 --- a/examples/phobos/std_experimental/source/app.d +++ b/examples/phobos/std_experimental/source/app.d @@ -73,3 +73,7 @@ pragma(mangle, "_D6python4conv11python_to_d__T2toTxS3std12experimental9allocator extern(C) void hack3() { } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std12experimental9allocator15building_blocks14allocator_list__T13AllocatorListTSQDdQDcQCr8showcase14mmapRegionListFmZ7FactoryTSQEyQExQEmQEf14null_allocator13NullAllocatorZQEe4NodeZ7_py_cmpUNbPSQIs3raw7_objectQriZQv") +private void hack4() { assert(0); } diff --git a/examples/phobos/std_file/source/app.d b/examples/phobos/std_file/source/app.d index b6668cdd..6c6e3687 100644 --- a/examples/phobos/std_file/source/app.d +++ b/examples/phobos/std_file/source/app.d @@ -21,3 +21,7 @@ void hack() { import std.file: dirEntries, SpanMode; auto id = typeid(dirEntries("path", "pattern", SpanMode.depth)); } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack1() { assert(0); } diff --git a/examples/phobos/std_net/source/app.d b/examples/phobos/std_net/source/app.d index 1d60a6a0..9d162d58 100644 --- a/examples/phobos/std_net/source/app.d +++ b/examples/phobos/std_net/source/app.d @@ -12,3 +12,7 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); } diff --git a/examples/phobos/std_zip/source/app.d b/examples/phobos/std_zip/source/app.d index 42d134c5..86ce4a20 100644 --- a/examples/phobos/std_zip/source/app.d +++ b/examples/phobos/std_zip/source/app.d @@ -10,3 +10,7 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); } diff --git a/pynih/source/python/conv/d_to_python.d b/pynih/source/python/conv/d_to_python.d index 2c2f3f66..c80cffa7 100644 --- a/pynih/source/python/conv/d_to_python.d +++ b/pynih/source/python/conv/d_to_python.d @@ -12,6 +12,21 @@ import std.datetime: Date, DateTime; import core.time: Duration; +PyObject* toPython(in bool val) @trusted @nogc { + import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct; + + auto pyTrue = cast(PyObject*) &_Py_TrueStruct; + auto pyFalse = cast(PyObject*) &_Py_FalseStruct; + + static PyObject* incAndRet(PyObject* obj) { + pyIncRef(obj); + return obj; + } + + return val ? incAndRet(pyTrue) : incAndRet(pyFalse); +} + + PyObject* toPython(T)(T value) @trusted if(isIntegral!T && !is(T == enum)) { import python.raw: PyLong_FromLong; return PyLong_FromLong(value); diff --git a/pynih/source/python/type.d b/pynih/source/python/type.d index fa049832..f2b2dd95 100644 --- a/pynih/source/python/type.d +++ b/pynih/source/python/type.d @@ -109,8 +109,11 @@ struct PythonType(T) { ) { _pyType.tp_richcompare = &PythonOpCmp!T._py_cmp; - } - } + } else + _pyType.tp_richcompare = &PythonCompare!T._py_cmp; + } else + _pyType.tp_richcompare = &PythonCompare!T._py_cmp; + static if(hasMember!(T, "opSlice")) { static if(AlwaysTry || __traits(compiles, &PythonIterViaList!T._py_iter)) @@ -1462,6 +1465,52 @@ private template PythonIndexAssign(T) { } } + +private template PythonCompare(T) { + + static extern(C) PyObject* _py_cmp(PyObject* self, PyObject* other, int op) nothrow { + + PyObject* impl() { + import python.conv.python_to_d: to; + import python.conv.d_to_python: toPython; + import python.raw: pyIncRef, _Py_NotImplementedStruct, Py_EQ, Py_LT, Py_LE, Py_NE, Py_GT, Py_GE; + + auto pyNotImplemented = cast(PyObject*) &_Py_NotImplementedStruct; + + static if(is(typeof(T.init < T.init) == bool)) + if(op == Py_LT) + return (self.to!T < other.to!T).toPython; + + static if(is(typeof(T.init <= T.init) == bool)) + if(op == Py_LE) + return (self.to!T <= other.to!T).toPython; + + static if(is(typeof(T.init == T.init) == bool)) + if(op == Py_EQ) + return (self.to!T == other.to!T).toPython; + + static if(is(typeof(T.init != T.init) == bool)) + if(op == Py_NE) + return (self.to!T != other.to!T).toPython; + + static if(is(typeof(T.init > T.init) == bool)) + if(op == Py_GT) + return (self.to!T > other.to!T).toPython; + + static if(is(typeof(T.init >= T.init) == bool)) + if(op == Py_GE) + return (self.to!T >= other.to!T).toPython; + + + pyIncRef(pyNotImplemented); + return pyNotImplemented; + } + + return noThrowable!impl; + } +} + + private bool isInstanceOf(T)(PyObject* obj) { import python.raw: PyObject_IsInstance; return cast(bool) PyObject_IsInstance(obj, cast(PyObject*) PythonType!T.pyType); diff --git a/tests/test_issues.py b/tests/test_issues.py index bad1dd71..0305346e 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -265,3 +265,14 @@ def test_method_delegate_safe_scope(): from issues import MethodWithScopeSafeDelegate m = MethodWithScopeSafeDelegate() assert m.fun(3, lambda i, d, s: i * 2) == 6 + + +def test_issue_268(): + import pytest + from issues import Issue268 + assert Issue268(1) != Issue268(2) + if is_pynih: + assert Issue268(42) == Issue268(42) + else: + with pytest.raises(AssertionError): + assert Issue268(42) == Issue268(42)