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.

Comments (0)

Files changed (7)

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() {}

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() {}

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

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() {}

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) {

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;
     }
 }
 

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))) {