1 module pybuffer;
2 
3 import std.stdio;
4 import mir.ndslice;
5 
6 
7 struct pybuffer {}
8 
9 mixin template MixinPyBufferWrappers(string _mod = __MODULE__) {
10     mixin("import mod =  " ~ _mod ~ ";");
11     mixin({
12             import std.conv : to;
13             import std.traits : Parameters, ReturnType;
14             string ret;
15             foreach (mem; __traits(allMembers, mod)) {
16                 foreach (attr; __traits(getAttributes, __traits(getMember, mod, mem))) {
17                     if (is(attr == pybuffer)) {
18                         mixin("alias R = ReturnType!(mod." ~ mem ~ ");");
19                         static assert(is(R == void), "@pybuffer function should return void");
20                         string args;
21                         string rargs;
22                         string converts = "  import mir.ndslice.connect.cpython;\n";
23                         converts ~= "  import std.stdio : writeln;\n";
24 
25                         mixin("alias Ps = Parameters!(mod." ~ mem ~ ");");
26                         foreach (i, P; Ps) {
27                             enum a = "a" ~ i.to!string;
28                             if (isSlice!P) {
29                                 args ~= " " ~ "ref Py_buffer " ~ a ~ " ,";
30                                 enum _a = "_a" ~ i.to!string;
31                                 converts ~= P.stringof ~ " " ~ _a ~ ";\n";
32                                 converts ~= "  {\n    auto err = fromPythonBuffer( " ~ _a ~ " , " ~ a ~ " );\n";
33                                 // TODO: enrich error messages
34                                 converts ~= "    if (err != PythonBufferErrorCode.success) { writeln(err, \"at param " ~ i.to!string ~ "\n\"); return err; }\n  }\n";
35                                 rargs ~= " " ~ _a ~ " ,";
36                             } else {
37                                 args ~= " " ~ P.stringof ~ " " ~ a ~ " ,";
38                                 rargs ~= " " ~ a ~ " ,";
39                             }
40                         }
41 
42                         // decleration
43                         string newName = "pybuffer_" ~ mem;
44                         // workaround to https://issues.dlang.org/show_bug.cgi?id=12575
45                         ret ~= "pragma(mangle, __traits(identifier, " ~ newName ~ "))\n";
46                         ret ~= "extern(C) auto " ~ newName ~ "(" ~ args[0..$-1] ~ ") {\n";
47 
48                         // conversions: pybuf -> ndslice
49                         ret ~= converts;
50 
51                         // exec function
52                         ret ~= "  " ~ mem ~ "(" ~ rargs[0..$-1] ~ ");\n";
53 
54                         // return success
55                         ret ~= "  return PythonBufferErrorCode.success;\n}\n\n";
56                     }
57                 }
58             }
59             return ret;
60         }()
61         );
62 }