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