1 /** 2 Reimplementations of pyd's class_wrap module 3 */ 4 module autowrap.python.pyd.class_wrap; 5 6 7 /** 8 Wraps a member function of the class. 9 10 Supports default arguments, typesafe variadic arguments, and python's 11 keyword arguments. 12 13 Params: 14 fn = The member function to wrap. 15 Options = Optional parameters. Takes Docstring!(docstring), PyName!(pyname), 16 and fn_t. 17 fn_t = The type of the function. It is only useful to specify this 18 if more than one function has the same name as this one. 19 pyname = The name of the function as it will appear in Python. Defaults to 20 fn's name in D 21 docstring = The function's docstring. Defaults to "". 22 */ 23 struct MemberFunction(alias fn, Options...) { 24 import pyd.def: Args; 25 26 alias args = Args!("", "", __traits(identifier, fn), "", Options); 27 28 static if(args.rem.length) { 29 alias fn_t = args.rem[0]; 30 } else { 31 alias fn_t = typeof(&fn); 32 } 33 34 mixin MemberFunctionImpl!(fn, args.pyname, fn_t, args.docstring); 35 } 36 37 private template MemberFunctionImpl(alias _fn, string name, fn_t, string docstring) { 38 import pyd.class_wrap: wrapped_method_list; 39 import pyd.references: PydTypeObject; 40 import pyd.def: def_selector; 41 import pyd.func_wrap: minArgs, method_wrap; 42 import util.typeinfo: ApplyConstness, constness; 43 import deimos.python.methodobject: PyMethodDef, PyCFunction, METH_VARARGS, METH_KEYWORDS; 44 45 alias func = def_selector!(_fn, fn_t).FN; 46 static assert(!__traits(isStaticFunction, func), 47 "Cannot register " ~ name ~ " because static member functions are not yet supported"); 48 alias /*StripSafeTrusted!*/fn_t func_t; 49 enum realname = __traits(identifier,func); 50 enum funcname = name; 51 enum min_args = minArgs!func; 52 enum bool needs_shim = false; // needed for the compile-time interface 53 54 static void call(string classname, T) () { // needed for the compile-time interface 55 alias cT = ApplyConstness!(T, constness!(typeof(func))); 56 static PyMethodDef empty = { null, null, 0, null }; 57 alias list = wrapped_method_list!(T); 58 59 list[$ - 1].ml_name = (name ~ "\0").ptr; 60 list[$ - 1].ml_meth = cast(PyCFunction) &method_wrap!(cT, func, classname ~ "." ~ name).func; 61 list[$ - 1].ml_flags = METH_VARARGS | METH_KEYWORDS; 62 list[$ - 1].ml_doc = (docstring~"\0").ptr; 63 list ~= empty; 64 // It's possible that appending the empty item invalidated the 65 // pointer in the type struct, so we renew it here. 66 PydTypeObject!T.tp_methods = list.ptr; 67 } 68 69 template shim(size_t i, T) { 70 import util.replace: Replace; 71 import std.traits: functionAttributes, variadicFunctionStyle, Variadic; 72 73 enum shim = Replace!(q{ 74 alias __pyd_p$i = Params[$i]; 75 $override ReturnType!(__pyd_p$i.func_t) $realname(ParameterTypeTuple!(__pyd_p$i.func_t) t) $attrs { 76 return __pyd_get_overload!("$realname", __pyd_p$i.func_t).func!(ParameterTypeTuple!(__pyd_p$i.func_t))("$name", t); 77 } 78 alias T.$realname $realname; 79 }, 80 "$i", i, "$realname", realname, "$name", name, 81 "$attrs", attrs_to_string(functionAttributes!func_t) ~ " " ~ tattrs_to_string!func_t(), 82 "$override", 83 //TODO: figure out what's going on here 84 (variadicFunctionStyle!func == Variadic.no ? "override": "")); 85 } 86 } 87 88 89 private string attrs_to_string(uint attrs) { 90 import std.traits: FunctionAttribute; 91 import std.compiler: version_major, version_minor; 92 93 string s = ""; 94 with(FunctionAttribute) { 95 if(attrs & pure_) s ~= " pure"; 96 if(attrs & nothrow_) s ~= " nothrow"; 97 if(attrs & ref_) s ~= " ref"; 98 if(attrs & property) s ~= " @property"; 99 if(attrs & trusted) s ~= " @trusted"; 100 if(attrs & safe) s ~= " @safe"; 101 if(attrs & nogc) s ~= " @nogc"; 102 static if(version_major == 2 && version_minor >= 67) { 103 if(attrs & return_) s ~= " return"; 104 } 105 } 106 return s; 107 } 108 109 110 private string tattrs_to_string(fn_t)() { 111 string s; 112 if(isConstFunction!fn_t) { 113 s ~= " const"; 114 } 115 if(isImmutableFunction!fn_t) { 116 s ~= " immutable"; 117 } 118 if(isSharedFunction!fn_t) { 119 s ~= " shared"; 120 } 121 if(isWildcardFunction!fn_t) { 122 s ~= " inout"; 123 } 124 return s; 125 } 126 127 private template isImmutableFunction(T...) if (T.length == 1) { 128 alias funcTarget!T func_t; 129 enum isImmutableFunction = is(func_t == immutable); 130 } 131 private template isConstFunction(T...) if (T.length == 1) { 132 alias funcTarget!T func_t; 133 enum isConstFunction = is(func_t == const); 134 } 135 private template isMutableFunction(T...) if (T.length == 1) { 136 alias funcTarget!T func_t; 137 enum isMutableFunction = !is(func_t == inout) && !is(func_t == const) && !is(func_t == immutable); 138 } 139 private template isWildcardFunction(T...) if (T.length == 1) { 140 alias funcTarget!T func_t; 141 enum isWildcardFunction = is(func_t == inout); 142 } 143 private template isSharedFunction(T...) if (T.length == 1) { 144 alias funcTarget!T func_t; 145 enum isSharedFunction = is(func_t == shared); 146 } 147 148 private template funcTarget(T...) if(T.length == 1) { 149 import std.traits; 150 static if(isPointer!(T[0]) && is(PointerTarget!(T[0]) == function)) { 151 alias PointerTarget!(T[0]) funcTarget; 152 }else static if(is(T[0] == function)) { 153 alias T[0] funcTarget; 154 }else static if(is(T[0] == delegate)) { 155 alias PointerTarget!(typeof((T[0]).init.funcptr)) funcTarget; 156 }else static assert(false); 157 }