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