Commits

ariovistus  committed 17bebb4

apparently conversion for delegates and fps didn't work. now it does.
added some playing with multithreading and pyd. seems not to die too
horribly.

  • Participants
  • Parent commits d1e7750

Comments (0)

Files changed (7)

File examples/pyd_unittests/make_object.d

 import pyd.pyd, pyd.embedded;
+import std.traits;
 import std.functional;
 import std.range;
 import std.algorithm;
     assert(python_to_d!(G1!"martin")(d_to_python(23)) == new G1!"martin"(23));
 }
 
+unittest {
+    auto func = function () {
+        return 22;
+    };
+
+    // typeof(func) distinct from int function()
+    assert(typeof(func).stringof == "int function() pure nothrow @safe");
+    auto py_func = py(func);
+    assert(py_func().to_d!int() == 22);
+
+    // but we'll convert typeof(func) back to int function()
+    auto refunc = py_func.to_d!(int function())();
+    assert(func is refunc);
+
+    // as well as original type
+    auto refunc2 = py_func.to_d!(typeof(func))();
+    assert(func is refunc2);
+
+    // or int function() pure
+    auto refunc3 = py_func.to_d!(
+            SetFunctionAttributes!(int function(), "D", 
+                FunctionAttribute.pure_))();
+    assert(func is refunc3);
+    // or int function() nothrow
+    auto refunc4 = py_func.to_d!(
+            SetFunctionAttributes!(int function(), "D", 
+                FunctionAttribute.nothrow_))();
+    assert(func is refunc4);
+
+    // etc
+
+    auto dg = delegate() {
+        return 42;
+    };
+    auto py_dg = py(dg);
+    assert(py_dg().to_d!int() == 42);
+}
+
 void main() {}

File examples/pyd_unittests/make_object3.d

 import pyd.pyd, pyd.embedded;
 import std.functional;
+import std.traits;
 import std.range;
 import std.algorithm;
 import std.exception;
     assert(python_to_d!(G1!"martin")(d_to_python(23)) == new G1!"martin"(23));
 }
 
+unittest {
+    auto func = function () {
+        return 22;
+    };
+
+    // typeof(func) distinct from int function()
+    assert(typeof(func).stringof == "int function() pure nothrow @safe");
+    auto py_func = py(func);
+    assert(py_func().to_d!int() == 22);
+
+    // but we'll convert typeof(func) back to int function()
+    auto refunc = py_func.to_d!(int function())();
+    assert(func is refunc);
+
+    // as well as original type
+    auto refunc2 = py_func.to_d!(typeof(func))();
+    assert(func is refunc2);
+
+    // or int function() pure
+    auto refunc3 = py_func.to_d!(
+            SetFunctionAttributes!(int function(), "D", 
+                FunctionAttribute.pure_))();
+    assert(func is refunc3);
+    // or int function() nothrow
+    auto refunc4 = py_func.to_d!(
+            SetFunctionAttributes!(int function(), "D", 
+                FunctionAttribute.nothrow_))();
+    assert(func is refunc4);
+
+    // etc
+
+    auto dg = delegate() {
+        return 42;
+    };
+    auto py_dg = py(dg);
+    assert(py_dg().to_d!int() == 42);
+}
+
 void main() {}

File examples/pyd_unittests/makefile

 	     -L-lpython3.2mu
 DC = dmd -unittest -property -debug -gc
 
-all: pydobject.x pydobject3.x make_object.x make_object3.x embedded.x embedded3.x func_wrap.x func_wrap3.x class_wrap.x class_wrap3.x def.x def3.x struct_wrap.x buffer.x
+all: pydobject.x pydobject3.x make_object.x make_object3.x embedded.x embedded3.x func_wrap.x func_wrap3.x class_wrap.x class_wrap3.x def.x def3.x struct_wrap.x buffer.x threading.x
 	./pydobject.x
 	./pydobject3.x
 	./make_object.x
 	./def.x
 	./def3.x
 	./buffer.x
+	./threading.x
 
 clean:
 	rm -f *.x

File examples/pyd_unittests/threading.d

+import pyd.pyd, pyd.embedded;
+import std.stdio;
+import std.range;
+import std.concurrency;
+import core.thread;
+import core.time;
+
+shared static this() {
+    py_init();
+}
+
+void non_python_block() {
+    try{
+        auto dg = {
+            receive(
+                    (string s) { writeln(s); }
+                   );
+        };
+        auto py_dg = py(dg);
+        alias py_def!(
+                "def a(fun):\n"
+                " fun()",
+                "sys",
+                void function(PydObject)) Caller;
+        Caller(py_dg);
+    }catch(Throwable t) {
+        writeln(t.toString());
+    }
+}
+
+void python_stuff1() {
+    py_stmts(
+            "for i in range(3):\n"
+            " print i"
+            );
+}
+
+unittest {
+
+    Tid tid = spawn(&non_python_block);
+    Thread.sleep(dur!"seconds"(1));
+    spawn(&python_stuff1);
+    Thread.sleep(dur!"seconds"(1));
+    send(tid, "finito!");
+    thread_joinAll();
+}
+
+
+void main() {}

File infrastructure/pyd/class_wrap.d

 
 // The class object, a subtype of PyObject
 template wrapped_class_object(T) {
-    extern(C)
-    struct wrapped_class_object {
-        mixin PydWrapObject_HEAD!(T);
+    // point wrapped_class_object!(void function() pure nothrow)
+    // to wrapped_class_object!(void function())
+    static if(hasFunctionAttrs!T) {
+        alias wrapped_class_object!(
+                SetFunctionAttributes!(T, functionLinkage!T, 
+                    FunctionAttribute.none)) wrapped_class_object;
+    }else {
+        extern(C)
+            struct wrapped_class_object {
+                mixin PydWrapObject_HEAD!(T);
+
+                static if(isFunctionPointer!T || isDelegate!T) {
+                    uint functionAttributes;
+                    string linkage; 
+                }
+            }
     }
 }
 
 }
 //
 template wrapped_class_type(T) {
-// The type object, an instance of PyType_Type
-    static PyTypeObject wrapped_class_type;
+    // point wrapped_class_type!(void function() pure nothrow)
+    // to wrapped_class_type!(void function())
+    static if(hasFunctionAttrs!T) {
+        alias wrapped_class_type!(
+                SetFunctionAttributes!(T, functionLinkage!T, 
+                    FunctionAttribute.none)) wrapped_class_type;
+    }else {
+        // The type object, an instance of PyType_Type
+        static PyTypeObject wrapped_class_type;
+    }
 }
 
 // A mapping of all class references that are being held by Python.
  * the conversion functions (see make_object.d), but possibly useful elsewhere.
  */
 template is_wrapped(T) {
-    bool is_wrapped = false;
+    // point is_wrapped!(void function() pure nothrow)
+    // to is_wrapped!(void function())
+    static if(hasFunctionAttrs!T) {
+        alias is_wrapped!(SetFunctionAttributes!(T, functionLinkage!T, 
+                    FunctionAttribute.none)) is_wrapped;
+    }else {
+        bool is_wrapped = false;
+    }
 }
 
 // The list of wrapped methods for this class.
     alias wrapped_class_type!(T) type;
     wrapped_object* self = cast(wrapped_object*)_self;
     if (!is_wrapped!(T)) {
-        throw new Exception(format("Error extracting D object: Type %s is not wrapped.",typeid(T).toString()));
+        throw new Exception(format(
+                    "Error extracting D object: Type %s is not wrapped.",
+                    typeid(T).toString()));
     }
     if (self is null) {
         throw new Exception("Error extracting D object: 'self' was null!");
     }
     static if (is(T == class)) {
         if (cast(Object)(self.d_obj) is null) {
-            throw new Exception("Error extracting D object: Reference was not castable to Object!");
+            throw new Exception(
+                    "Error extracting D object: "
+                    "Reference was not castable to Object!");
         }
         if (cast(T)cast(Object)(self.d_obj) is null) {
-            throw new Exception(format("Error extracting D object: Object was not castable to type %s.",typeid(T).toString()));
+            throw new Exception(format(
+                        "Error extracting D object: "
+                        "Object was not castable to type %s.",
+                        typeid(T).toString()));
         }
     }
-    return self.d_obj;
+    static if(hasFunctionAttrs!T && !is(typeof(self.d_obj) == T)) {
+        // check that casting is safe enough
+        if(self.linkage != functionLinkage!T) {
+            // can't cast away linkage!
+            // TODO: should we wrap this somehow?
+            throw new Exception(format(
+                        "trying to convert a extern(\"%s\") "
+                        "%s to extern(\"%s\")",
+                        self.linkage, (isDelegate!T ? "delegate":"function"),
+                        functionLinkage!T));
+        }else if((~self.functionAttributes & functionAttributes!T) == 0) {
+            // same type or only casting away attrs - ok!
+            return cast(T) self.d_obj;
+        }else{
+            string attrs_to_string(uint attrs) {
+                string s = "";
+                with(FunctionAttribute) {
+                    if(attrs & pure_) s ~= " pure";
+                    if(attrs & nothrow_) s ~= " nothrow";
+                    if(attrs & ref_) s ~= " ref";
+                    if(attrs & property) s ~= " @property";
+                    if(attrs & trusted) s ~= " @trusted";
+                    if(attrs & safe) s ~= " @safe";
+                }
+                return s;
+            }
+            throw new Exception(format(
+                        "trying to convert %s%s to %s",
+                        SetFunctionAttributes!(T, 
+                            functionLinkage!T, 
+                            FunctionAttribute.none).stringof,
+                        attrs_to_string(self.functionAttributes),
+                        T.stringof));
+        }
+    }else {
+        return self.d_obj;
+    }
 }
 
 /*
 void WrapPyObject_SetObj(T) (PyObject* _self, T t) {
     alias wrapped_class_object!(T) obj;
     obj* self = cast(obj*)_self;
+    static if(isFunctionPointer!T || isDelegate!T) {
+        self.functionAttributes = functionAttributes!T;
+        self.linkage = functionLinkage!T;
+    }
     if (t is self.d_obj) return;
     // Clean up the old object, if there is one
     if (self.d_obj !is null) {

File infrastructure/pyd/func_wrap.d

 
 import std.traits;
 
+template hasFunctionAttrs(T) {
+    static if(isDelegate!T || isFunctionPointer!T) {
+        enum bool hasFunctionAttrs = functionAttributes!T != 
+            FunctionAttribute.none;
+    }else{
+        enum bool hasFunctionAttrs = false;
+    }
+}
+
 // Builds a callable Python object from a delegate or function pointer.
-void PydWrappedFunc_Ready(T)() {
+void PydWrappedFunc_Ready(S)() {
+    static if(hasFunctionAttrs!S) {
+        alias SetFunctionAttributes!(S, 
+                functionLinkage!S, 
+                FunctionAttribute.none) T;
+    }else{
+        alias S T;
+    }
     alias wrapped_class_type!(T) type;
     alias wrapped_class_object!(T) obj;
     if (!is_wrapped!(T)) {
-        type.ob_type = PyType_Type_p;
+        init_PyTypeObject!T(type);
+        Py_SET_TYPE(&type, &PyType_Type);
         type.tp_basicsize = obj.sizeof;
-        type.tp_name = "PydFunc";
+        type.tp_name = "PydFunc".ptr;
         type.tp_flags = Py_TPFLAGS_DEFAULT;
 
         type.tp_call = &wrapped_func_call!(T).call;
 
         PyType_Ready(&type);
-        is_wrapped!(T) = true;
-        //wrapped_classes[typeid(T)] = true;
+        is_wrapped!T = true;
     }
 }
 

File infrastructure/pyd/make_object.d

             }
         }
         return dict;
-    } else static if (is(T == delegate) || is(T == function)) {
+    } else static if (isDelegate!T || isFunctionPointer!T) {
         PydWrappedFunc_Ready!(T)();
         return WrapPyObject_FromObject(t);
     } else static if (is(T : PydObject)) {
         } else if (PyCallable_Check(o)) {
             return PydCallable_AsDelegate!(T)(o);
         }// else could_not_convert!(T)(o);
-    } else static if (is(T == function)) {
+    } else static if (isDelegate!T || isFunctionPointer!T) {
         // We can only make it a function pointer if we originally wrapped a
         // function pointer.
         if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) {