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 enum shim = Replace!(q{ 72 alias __pyd_p$i = Params[$i]; 73 $override ReturnType!(__pyd_p$i.func_t) $realname(ParameterTypeTuple!(__pyd_p$i.func_t) t) $attrs { 74 return __pyd_get_overload!("$realname", __pyd_p$i.func_t).func!(ParameterTypeTuple!(__pyd_p$i.func_t))("$name", t); 75 } 76 alias T.$realname $realname; 77 }, 78 "$i", i, "$realname", realname, "$name", name, 79 "$attrs", attrs_to_string(functionAttributes!func_t) ~ " " ~ tattrs_to_string!func_t(), 80 "$override", 81 //TODO: figure out what's going on here 82 (variadicFunctionStyle!func == Variadic.no ? "override": "")); 83 } 84 }