1 module gfx.bindings.core;
2 
3 // Dynamic bindings facility
4 
5 /// A handle to a shared library
6 alias SharedLib = void*;
7 /// A handle to a shared library symbol
8 alias SharedSym = void*;
9 
10 /// Opens a shared library.
11 /// Return null in case of failure.
12 SharedLib openSharedLib(string name);
13 
14 /// Load a symbol from a shared library.
15 /// Return null in case of failure.
16 SharedSym loadSharedSym(SharedLib lib, string name);
17 
18 /// Close a shared library
19 void closeSharedLib(SharedLib lib);
20 
21 
22 
23 version(Posix)
24 {
25     import std.string : toStringz;
26     import core.sys.posix.dlfcn;
27 
28     SharedLib openSharedLib(string name)
29     {
30         return dlopen(toStringz(name), RTLD_LAZY);
31     }
32 
33     SharedSym loadSharedSym(SharedLib lib, string name)
34     {
35         return dlsym(lib, toStringz(name));
36     }
37 
38     void closeSharedLib(SharedLib lib)
39     {
40         dlclose(lib);
41     }
42 }
43 version(Windows)
44 {
45     import std.string : toStringz;
46     import core.sys.windows.winbase;
47 
48     SharedLib openSharedLib(string name)
49     {
50         return LoadLibraryA(toStringz(name));
51     }
52 
53     SharedSym loadSharedSym(SharedLib lib, string name)
54     {
55         return GetProcAddress(lib, toStringz(name));
56     }
57 
58     void closeSharedLib(SharedLib lib)
59     {
60         FreeLibrary(lib);
61     }
62 }
63 
64 /// Utility that open a shared library and load symbols from it.
65 class SharedLibLoader
66 {
67     import std.typecons : Flag, Yes, No;
68     private SharedLib _lib;
69     private string _libName;
70 
71     /// Load the shared libraries and call bindSymbols if succesful.
72     void load (string[] libNames)
73     {
74         foreach (ln; libNames)
75         {
76             _lib = openSharedLib(ln);
77             if (_lib)
78             {
79                 _libName = ln;
80                 break;
81             }
82         }
83         if (!_lib)
84         {
85             import std.conv : to;
86             throw new Exception(
87                 "Cannot load one of shared libs " ~ libNames.to!string
88             );
89         }
90         bindSymbols();
91     }
92 
93     /// Direct handle access
94     public @property SharedLib handle()
95     {
96         return _lib;
97     }
98 
99     /// Returns whether the shared library is open.
100     public @property bool loaded() const
101     {
102         return _lib !is null;
103     }
104 
105     /// Returns the name of the shared library that was open.
106     /// Empty string if not loaded.
107     public @property string libName() const
108     {
109         return _libName;
110     }
111 
112     /// Bind a symbol, using the function pointer symbol name.
113     void bind(alias f)(Flag!"optional" optional = No.optional)
114     {
115         immutable name = f.stringof;
116         if (f !is null)
117         {
118             throw new Exception("Tentative to bind already bound symbol "~ name);
119         }
120         auto sym = loadSharedSym(_lib, name);
121         if (!sym && !optional)
122         {
123             throw new Exception("Cannot load symbol "~name~" from "~_libName~".");
124         }
125         f = cast(typeof(f)) sym;
126     }
127 
128     /// Subclasses can override this to bind all the necessary symbols.
129     /// Default implementation does nothing.
130     void bindSymbols()
131     {}
132 }