1 module dorm.lib.ffi_wrap; 2 3 // public import dorm.lib.ffi_impl; 4 5 import std.array; 6 import std.conv; 7 import std.stdio; 8 import std.traits; 9 import std.typecons : tuple; 10 11 private static import dorm.lib.ffi_impl; 12 13 private string formatArgs(T...)(T args) 14 { 15 auto ret = appender!string; 16 bool first = true; 17 static foreach (arg; args) 18 { 19 if (!first) 20 ret ~= ", "; 21 first = false; 22 ret ~= "\n\t"; 23 ret ~= formatArg(arg); 24 } 25 static if (args.length > 0) 26 ret ~= "\n"; 27 return ret.data; 28 } 29 30 private string formatArg(T)(T value) 31 { 32 static if (is(T : const(FFICondition)*) || is(T : FFICondition*)) 33 { 34 return value ? formatArg(*value) : "(no condition)"; 35 } 36 else static if (is(T == enum)) 37 { 38 static if (is(OriginalType!T == U*, U)) 39 return T.stringof ~ "@" ~ (cast(size_t)value).to!string(16); 40 else 41 return T.stringof ~ "." ~ value.to!string; 42 } 43 else static if (is(T == U*, U)) 44 return U.stringof ~ "@" ~ (cast(size_t)value).to!string(16); 45 else 46 { 47 return value.to!string; 48 } 49 } 50 51 size_t dormTraceFun(T...)(bool withRet, string method, T args) 52 { 53 static __gshared size_t id; 54 if (withRet) 55 { 56 auto reqId = id++; 57 stderr.writeln("[trace] #", reqId, " ", method, " (", formatArgs(args), ")"); 58 return reqId; 59 } 60 else 61 { 62 stderr.writeln("[trace] (void) ", method, "(", formatArgs(args), ")"); 63 return 0; 64 } 65 } 66 67 void dormTraceRetval(T)(size_t reqid, T retval) 68 { 69 stderr.writeln("[trace] #", reqid, " -> returned ", retval); 70 } 71 72 void dormTraceCallback(scope dorm.lib.ffi_impl.RormError error) 73 { 74 if (error) 75 stderr.writeln("[trace] Callback (failed) -> ", error.makeException.msg); 76 else 77 stderr.writeln("[trace] Callback success"); 78 } 79 80 void dormTraceCallback(T)(scope T result, scope dorm.lib.ffi_impl.RormError error) 81 { 82 if (error) 83 stderr.writeln("[trace] Callback (failed) -> ", error.makeException.msg); 84 else 85 stderr.writeln("[trace] Callback success: ", formatArg(result)); 86 } 87 88 void dormTraceSyncCallback(scope dorm.lib.ffi_impl.RormError error) 89 { 90 if (error) 91 stderr.writeln("[trace] Sync Callback (failed) -> ", error.makeException.msg); 92 else 93 stderr.writeln("[trace] Sync Callback success"); 94 } 95 96 void dormTraceSyncCallback(T)(scope T result, scope dorm.lib.ffi_impl.RormError error) 97 { 98 if (error) 99 stderr.writeln("[trace] Sync Callback (failed) -> ", error.makeException.msg); 100 else 101 stderr.writeln("[trace] Sync Callback success: ", formatArg(result)); 102 } 103 104 // --------------------------------------------------------------------------------- 105 106 private static string generateTracer(string symbolName)() 107 { 108 alias symbol = __traits(getMember, dorm.lib.ffi_impl, symbolName); 109 110 static if (is(ReturnType!symbol == void)) 111 { 112 return "extern(D) " ~ ReturnType!symbol.stringof 113 ~ " " ~ symbolName ~ "_wrapper(Parameters!(dorm.lib.ffi_impl." ~ symbolName ~ ")) { 114 import dorm.lib.ffi_impl : " ~ symbolName ~ "; 115 dormTraceFun(false, `" ~ symbolName ~ "`, __traits(parameters)); 116 " ~ symbolName ~ "(__traits(parameters)); 117 } 118 alias " ~ symbolName ~ " = " ~ symbolName ~ "_wrapper;"; 119 } 120 else 121 { 122 return "extern(D) " ~ ReturnType!symbol.stringof 123 ~ " " ~ symbolName ~ "_wrapper(Parameters!(dorm.lib.ffi_impl." ~ symbolName ~ ")) { 124 import dorm.lib.ffi_impl : " ~ symbolName ~ "; 125 auto reqid = dormTraceFun(true, `" ~ symbolName ~ "`, __traits(parameters)); 126 127 auto retval = " ~ symbolName ~ "(__traits(parameters)); 128 dormTraceRetval(reqid, retval); 129 return retval; 130 } 131 alias " ~ symbolName ~ " = " ~ symbolName ~ "_wrapper;"; 132 } 133 } 134 135 static foreach (symbol; __traits(allMembers, dorm.lib.ffi_impl)) 136 { 137 static if (__traits(compiles, mixin("dorm.lib.ffi_impl.", symbol))) 138 { 139 static if (is(typeof(__traits(getMember, dorm.lib.ffi_impl, symbol)) == function) 140 && __traits(getLinkage, __traits(getMember, dorm.lib.ffi_impl, symbol)) == "C") 141 { 142 mixin(generateTracer!symbol); 143 } 144 else static if (symbol != "object" && symbol != "dorm") 145 mixin("alias ", symbol , " = dorm.lib.ffi_impl.", symbol , ";"); 146 } 147 } 148