1 /*
2                                     __
3                                    / _|
4   __ _ _   _ _ __ ___  _ __ __ _  | |_ ___  ___ ___
5  / _` | | | | '__/ _ \| '__/ _` | |  _/ _ \/ __/ __|
6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \
7  \__,_|\__,_|_|  \___/|_|  \__,_| |_| \___/|___/___/
8 
9 Copyright © 2013-2016, Mike Parker.
10 Copyright © 2016, 渡世白玉.
11 Copyright © 2018, Michael D. Parker
12 Copyright © 2018-2019, Aurora Free Open Source Software.
13 
14 This file is part of the Aurora Free Open Source Software. This
15 organization promote free and open source software that you can
16 redistribute and/or modify under the terms of the GNU Lesser General
17 Public License Version 3 as published by the Free Software Foundation or
18 (at your option) any later version approved by the Aurora Free Open Source
19 Software Organization. The license is available in the package root path
20 as 'LICENSE' file. Please review the following information to ensure the
21 GNU Lesser General Public License version 3 requirements will be met:
22 https://www.gnu.org/licenses/lgpl.html .
23 
24 Alternatively, this file may be used under the terms of the GNU General
25 Public License version 3 or later as published by the Free Software
26 Foundation. Please review the following information to ensure the GNU
27 General Public License requirements will be met:
28 https://www.gnu.org/licenses/gpl-3.0.html.
29 
30 NOTE: All products, services or anything associated to trademarks and
31 service marks used or referenced on this file are the property of their
32 respective companies/owners or its subsidiaries. Other names and brands
33 may be claimed as the property of others.
34 
35 For more info about intellectual property visit: aurorafoss.org or
36 directly send an email to: contact (at) aurorafoss.org .
37 
38 This file is an improvement of an existing code, part of DerelictUtil
39 from DerelictOrg. Check it out at derelictorg.github.io .
40 
41 This file is an improvement of an existing code, developed by 渡世白玉
42 and available on github at https://github.com/huntlabs/DerelictUtil .
43 
44 This file is an improvement of an existing code, part of bindbc-loader
45 from BindBC. Check it out at github.com/BindBC/bindbc-loader .
46 */
47 
48 module riverd.builder;
49 
50 import std.traits;
51 
52 /** Dynamic Library Loader Builder
53  * This template combined with a mixin,
54  * build automatically a dynamic loader for a specific library.
55  * @param handle_name handle name, normally the library name
56  * @param libs possible libraries names array
57  * @param T alias to dynfun specific library module
58  * @param required strictly require, otherwise throw an exception
59  */
60 template DylibLoaderBuilder(string handle_name, string[] libs, alias T, bool required = false)
61 {
62 	string _buildLoader(string handle_name, string[] libs, alias T, bool required = false)()
63 	{
64 		static if(required)
65 			enum dthrow = "true";
66 		else
67 			enum dthrow = "false";
68 
69 		string ret = "\n";
70 
71 		import std.string : toLower;
72 
73 		version(D_BetterC)
74 		{
75 			// implementation of dynamic loader for -betterC
76 			import std.array : join;
77 			ret ~= "void* dylib_load_" ~ toLower(handle_name) ~ "() { void* handle;";
78 			foreach(string lib; libs)
79 				ret ~= "if(handle is null) handle = dylib_load(\"" ~ lib ~ "\");\n";
80 			ret ~= "if(handle is null) return null;\n\n";
81 		}
82 		else {
83 			// create dylib_load function for garbage collected loader
84 			ret ~= "pragma(inline, true) void* dylib_load_" ~ toLower(handle_name)
85 				~ "() { return cast(void*)(new " ~ handle_name ~ "DylibLoader()); }\n class "
86 				~ handle_name ~ "DylibLoader : DylibLoader {\nthis() { super(";
87 
88 			string tmp = "[";
89 			foreach(string t; libs)
90 				tmp~="\""~t~"\",";
91 			tmp= tmp[0 .. $-1];
92 			tmp~="]";
93 
94 			ret ~= tmp ~ "); }\noverride void loadSymbols() {\n";
95 		}
96 		
97 		foreach(mem; __traits(derivedMembers, T))
98 		{
99 			static if( isFunctionPointer!(__traits(getMember, T, mem)))
100 			{
101 				version(D_BetterC) ret ~= "\tdylib_bindSymbol(handle,cast(void**)&" ~ mem ~ ", \"" ~ mem ~ "\");\n";
102 				else ret ~= "\tbindFunc(" ~ mem ~ ", \"" ~ mem ~ "\", " ~ dthrow ~ ");\n";
103 			}
104 		}
105 		version(D_BetterC)
106 		{
107 			ret ~= "return handle; }";
108 		}
109 		else {
110 			ret ~= "}}";
111 		}
112 		return ret;
113 	}
114 
115 	enum DylibLoaderBuilder = _buildLoader!(handle_name, libs, T, required)();
116 }
117 
118 /** Dynamic Library Type Builder
119  * This template combined with a mixin,
120  * build automatically the types needed by the dynamic loader.
121  * @param T alias to dynfun specific library module
122  */
123 template DylibTypeBuilder(alias T)
124 {
125 	string _buildTypes(alias T)()
126 	{
127 		string ret;
128 		foreach(func; __traits(derivedMembers, T))
129 		{
130 			alias ftype = __traits(getMember, T, func);
131 			static if(isFunction!(ftype))
132 				ret ~= "alias da_" ~ func ~ " = "~ ReturnType!(ftype).stringof ~ " function" ~ Parameters!(ftype).stringof ~ ";\n";
133 		}
134 
135 		return ret;
136 	}
137 
138 	enum DylibTypeBuilder = _buildTypes!(T)();
139 }