1 module python.boilerplate; 2 3 4 import std.traits: isFunction; 5 6 7 string createModuleRecipe(Module module_, alias cfunctions, alias aggregates = Aggregates!()) 8 () 9 { 10 import std.format: format; 11 12 return q{ 13 extern(C) export auto PyInit_%s() nothrow { 14 import python.cooked: createModule; 15 import python.boilerplate: commonInit, Module, CFunctions, Aggregates; 16 17 commonInit; 18 19 return createModule!( 20 Module("%s"), 21 %s, 22 %s, 23 ); 24 } 25 26 }.format( 27 module_.name, 28 module_.name, 29 cfunctions.stringof, 30 aggregates.stringof, 31 ); 32 } 33 34 35 void commonInit() nothrow { 36 import python.raw: pyDateTimeImport; 37 import core.runtime: rt_init; 38 39 try 40 rt_init; 41 catch(Exception _) 42 assert(0); 43 } 44 45 /// For a nicer API 46 struct Module { 47 string name; 48 } 49 50 51 /// For a nicer API 52 struct CFunctions(Args...) { 53 54 import std.meta: staticMap; 55 56 enum length = Args.length; 57 58 private template toCFunction(alias F) { 59 static if(isFunction!F) 60 alias toCFunction = CFunction!F; 61 else 62 alias toCFunction = F; 63 } 64 65 alias functions = staticMap!(toCFunction, Args); 66 67 static string stringifySymbols() { 68 import std.array: join; 69 70 string[] ret; 71 72 static foreach(func; functions) 73 ret ~= `CFunction!(` ~ __traits(identifier, func.symbol) ~ `, "` ~ func.identifier ~ `")`; 74 75 return ret.join(", "); 76 } 77 } 78 79 /// For a nicer API 80 struct CFunction(alias F, string I = "") if(isFunction!F) { 81 82 alias symbol = F; 83 84 static if(I == "") 85 enum identifier = __traits(identifier, symbol); 86 else 87 enum 88 identifier = I; 89 } 90 91 92 /// A list of aggregates to wrap 93 struct Aggregates(T...) { 94 alias Types = T; 95 96 static string stringifyTypes() { 97 import std.array: join; 98 string[] ret; 99 100 static foreach(T; Types) 101 ret ~= T.stringof; 102 103 return ret.join(", "); 104 } 105 }