1 /// 2 module ssll; 3 4 import core.sys.posix.dlfcn; 5 6 import std.string : toStringz; 7 import std.exception : enforce; 8 9 struct ApiUDA { string libname; } 10 auto api(string lname="lib") { return ApiUDA(lname); } 11 12 string apiFunctionPointerName(string f) { return "__"~f~"_dlg"; } 13 14 /// 15 void* loadLibrary(string name) 16 { 17 return dlopen(name.toStringz, RTLD_LAZY); 18 } 19 20 /// 21 void unloadLibrary(ref void* lib) 22 { 23 dlclose(&lib); 24 lib = null; 25 } 26 27 private enum __initDeclare = q{ 28 import std.meta; 29 import std.typecons; 30 import std.traits; 31 import std.string; 32 import core.sys.posix.dlfcn : dlsym; 33 34 enum __dimmy; 35 alias __this = AliasSeq!(__traits(parent, __dimmy))[0]; 36 enum __name = __traits(identifier, __this); 37 }; 38 39 private enum __callDeclare = q{ 40 enum __pit = [ParameterIdentifierTuple!__this]; 41 static if (!__pit.length) enum __params = ""; 42 else enum __params = "%-(%s, %)".format(__pit); 43 enum __call = "__fnc(%s);".format(__params); 44 static if (is(ReturnType!__this == void)) 45 enum __result = __call; 46 else 47 enum __result = "return " ~ __call; 48 mixin(__result); 49 }; 50 51 string rtLib() 52 { 53 return __initDeclare ~ q{ 54 mixin("auto __fnc = %s;".format(apiFunctionPointerName(__name))); 55 } ~ __callDeclare; 56 } 57 58 mixin template apiSymbols() 59 { 60 import std.meta; 61 import std.typecons; 62 import std.traits; 63 64 enum __dimmy; 65 66 template funcsByUDA(alias symbol, uda) 67 { 68 template impl(lst...) 69 { 70 static if (lst.length == 1) 71 { 72 static if (is(typeof(__traits(getMember, symbol, lst[0])) == function)) 73 { 74 alias ff = AliasSeq!(__traits(getMember, symbol, lst[0]))[0]; 75 static if (hasUDA!(ff, uda)) alias impl = AliasSeq!(ff); 76 else alias impl = AliasSeq!(); 77 } 78 else alias impl = AliasSeq!(); 79 } 80 else alias impl = AliasSeq!(impl!(lst[0..$/2]), impl!(lst[$/2..$])); 81 } 82 83 alias funcsByUDA = impl!(__traits(allMembers, symbol)); 84 } 85 86 alias apiFuncs = funcsByUDA!(__traits(parent, __dimmy), ApiUDA); 87 88 void loadApiSymbols() 89 { 90 import std.string; 91 import core.sys.posix.dlfcn; 92 foreach (f; apiFuncs) 93 { 94 enum libname = getUDAs!(f, ApiUDA)[$-1].libname; 95 enum fname = __traits(identifier, f); 96 enum pname = apiFunctionPointerName(fname); 97 mixin(format(`%2$s = cast(typeof(%2$s))dlsym(%3$s, "%1$s".toStringz);`, fname, pname, libname)); 98 } 99 } 100 101 mixin funcPointers!apiFuncs; 102 } 103 104 mixin template funcPointers(funcs...) 105 { 106 import std.string; 107 static if (funcs.length == 0) {} 108 else static if (funcs.length == 1) 109 { 110 alias __this = funcs[0]; 111 mixin(`private extern(C) @nogc nothrow ReturnType!__this function(Parameters!__this) %s;` 112 .format(apiFunctionPointerName(__traits(identifier, __this)))); 113 } 114 else 115 { 116 mixin funcPointers!(funcs[0..$/2]); 117 mixin funcPointers!(funcs[$/2..$]); 118 } 119 }