1 module dynamic;
2 
3 enum SymbolSet { all, skipDeprecated }
4 
5 mixin template dynamicBinding(alias mod, SymbolSet symbols = SymbolSet.all)
6 {
7 	import core.runtime : Runtime;
8 	import std.traits : ReturnType, ParameterTypeTuple, functionLinkage;
9 	import std.format : format;
10 
11 	alias _prototypes = prototypes!(mod, symbols);
12 
13 	private static string mixins()
14 	{
15 		string ret;
16 		foreach (i, proto; _prototypes) {
17 			ret ~= q{
18 				extern(%2$s) alias P_%1$s = ReturnType!(_prototypes[%3$d]) function(ParameterTypeTuple!(_prototypes[%3$d]));
19 				P_%1$s p_%1$s;
20 				extern(%2$s) ReturnType!(_prototypes[%3$d]) %1$s(ParameterTypeTuple!(_prototypes[%3$d]) params) {
21 					assert(p_%1$s !is null, "Function not loaded: %1$s");
22 					return p_%1$s(params);
23 				}
24 			}.format(__traits(identifier, proto), functionLinkage!proto, i);
25 		}
26 		return ret;
27 	}
28 	mixin(mixins());
29 
30 	void loadBinding(scope string[] library_files)
31 	{
32 		import std.conv : to;
33 		import std.format : format;
34 		import std.utf : toUTF16z;
35 		import std..string : toStringz;
36 		version (Windows) import core.sys.windows.windows : LoadLibraryW;
37 		else import core.sys.posix.dlfcn : dlopen, RTLD_LAZY;
38 
39 		foreach (f; library_files) {
40 			version (Windows) void* lib = LoadLibraryW(f.toUTF16z);
41 			else void* lib = dlopen(f.toStringz(), RTLD_LAZY);
42 			if (!lib) continue;
43 
44 			foreach (proto; _prototypes) {
45 				mixin(q{
46 					p_%1$s = cast(P_%1$s)loadProc(lib, proto.mangleof);
47 					if (!p_%1$s)
48 						throw new Exception(
49 							format("Failed to load function '%%s' from %1$s",
50 							proto.mangleof));
51 				}.format(__traits(identifier, proto)));
52 			}
53 			return;
54 		}
55 
56 		throw new Exception(format("Failed to load any of the shared library candidates: %(%s, %)", library_files));
57 	}
58 }
59 
60 /// private
61 template prototypes(alias mod, SymbolSet symbols)
62 {
63 	import std.meta : AliasSeq, staticMap;
64 
65 	template Overloads(string name) {
66 		static if (symbols == SymbolSet.skipDeprecated && isDeprecated!(mod, name))
67 			alias Overloads = AliasSeq!();
68 		else
69 			alias Overloads = AliasSeq!(__traits(getOverloads, mod, name));
70 	}
71 	alias functions = staticMap!(Overloads, AliasSeq!(__traits(allMembers, mod)));
72 
73 	/*template impl(size_t idx) {
74 		static if (idx < members.length) {
75 			alias impl = AliasSeq!(members[i], impl
76 		} else alias impl = AliasSeq!();
77 	}*/
78 	alias prototypes = functions;
79 }
80 
81 // crude workaround to gag deprecation warnings
82 private enum isDeprecated(alias parent, string symbol) =
83 	is(typeof({
84 		static assert(__traits(isDeprecated, __traits(getMember, parent, symbol)));
85 	}));
86 
87 /// private
88 void* loadProc(void* lib, string name)
89 {
90 	import std..string : toStringz;
91 
92 	version (Windows) {
93 		import core.sys.windows.windows;
94 		return GetProcAddress(lib, name.toStringz());
95 	} else {
96 		import core.sys.posix.dlfcn : dlsym;
97 		return dlsym(lib, name.toStringz());
98 	}
99 }