1 module vulkanish.helpers.functions;
2 
3 import std.traits;
4 static if (!is(typeof(Unconst)))
5 	import core.internal.traits : Unconst;
6 
7 import erupted;
8 import refedforeignptr;
9 
10 import vulkanish.helpers.internal;
11 import vulkanish.helpers.error;
12 import vulkanish.helpers.types;
13 import vulkanish.helpers.enums;
14 
15 import std.meta;
16 import std..string;
17 import std.conv;
18 import std.typecons;
19 
20 alias vshEnumerateAlt(string name) = vshEnumerate!(functionMixin!("vk"~name));
21 alias vshEnumerate(string name) = vshEnumerate!(functionMixin!("vkEnumerate"~name));
22 template vshEnumerate(alias f_unenforced)
23 ////if (isCallable!f_unenforced)
24 {
25 	static assert(isCallable!f_unenforced);
26 	alias f = enforced!f_unenforced;
27 	alias Params = Parameters!f;
28 	PointerTarget!(Params[$-1])[] vshEnumerate(Params[0..$-2] args) {
29 		uint count;
30 		f(args, &count, null);
31 		if (count == 0)
32 			return [];
33 		auto outArray = new PointerTarget!(Params[$-1])[count];
34  		f(args, &count, outArray.ptr);
35 		return outArray;
36 	}
37 }
38 
39 
40 alias vshCall(alias f) = vsh!f;
41 alias vsh(string name) = vsh!(functionMixin!("vk"~name));
42 template vsh(alias f_unenforced)
43 ////if (isCallable!f_unenforced)
44 {
45 	static assert(isCallable!f_unenforced);
46 	alias f = enforced!f_unenforced;
47 	alias Params = Parameters!f;
48 	
49 	////template hasAltType(T) {
50 	////	static if (isPointer!T && is(Unconst!(PointerTarget!T) == struct))
51 	////		enum hasAltType = __traits(identifier, Unconst!(PointerTarget!T)).endsWith("CreateInfo");
52 	////	else
53 	////		enum hasAltType = false;
54 	////}
55 	////template AltType(T) {
56 	////	static if (hasAltType!T)
57 	////		alias AltType = PointerTarget!T;
58 	////	else
59 	////		alias AltType = T;
60 	////}
61 	////template altArg(T)(T arg) {
62 	////	
63 	////}
64 	////mixin forParams!Params;
65 	////static if (anySatisfy!(hasAltType,Params))
66 	////	mixin forParams!(staticMap!(AltType,Params));
67 	////mixin template forParams(Params...) {
68 	auto vsh(Params args) {
69 		f(args);
70 	}
71 	// Second to last argument allocator.
72 	static if (is(Params[$-2] == const(VkAllocationCallbacks)*)) {
73 		// Given no allocator
74 		auto vsh(Params[0..$-2] args, Params[$-1] lastArg) {
75 			f(args,null,lastArg);
76 		}
77 	}
78 	// Last argument allocator.
79 	static if (is(Params[$-1] == const(VkAllocationCallbacks)*)) {
80 		// Given no allocator
81 		auto vsh(Params[0..$-1] args) {
82 			f(args,null);
83 		}
84 	}
85 	// Returning through last argument as pointer.
86 	else static if (isPointer!(Params[$-1]) && __traits(compiles, {PointerTarget!(Params[$-1]) outPtr;})) {
87 		// Given no out ptr.
88 		auto vsh(Params[0..$-1] args) {
89 			PointerTarget!(Params[$-1]) outPtr;
90 			f(args,&outPtr);
91 			return outPtr;
92 		}
93 		// Second to last argument allocator.
94 		static if (is(Params[$-2] == const(VkAllocationCallbacks)*)) {
95 			// Given no allocator nor out ptr.
96 			auto vsh(Params[0..$-2] args) {
97 				PointerTarget!(Params[$-1]) outPtr;
98 				f(args,null,&outPtr);
99 				return outPtr;
100 			}
101 		}
102 	}
103 	////}
104 }
105 
106 template vshDestroy(Ts...) if (Ts.length>0 && isHandleType!(Ts[$-1])) {
107 	enum name = handleName!(Ts[$-1]);
108 	alias f = functionMixin!("vkDestroy"~name);
109 	
110 	auto vshDestroy(Ts args, const(VkAllocationCallbacks)* allocator) {
111 		f(args,allocator);
112 	}
113 	auto vshDestroy(Ts args) {
114 		f(args,null);
115 	}
116 }
117 template vshDestroyRange(Ts...) if (Ts.length>0 && isHandleType!(ForeachType!(Ts[$-1]))) {
118 	enum name = handleName!(ForeachType!(Ts[$-1]));
119 	alias f = functionMixin!("vkDestroy"~name);
120 	import std.algorithm;
121 	
122 	auto vshDestroyRange(Ts args, const(VkAllocationCallbacks)* allocator) {
123 		args[$-1].each!(h=>f(args[0..$-1],h,allocator));
124 	}
125 	auto vshDestroyRange(Ts args) {
126 		args[$-1].each!(h=>f(args[0..$-1],h,null));
127 	}
128 }
129 template vshFrees(Ts...) if (Ts.length>0 && isHandleType!(ForeachType!(Ts[$-1]))) {
130 	enum name = handleName!(ForeachType!(Ts[$-1]));
131 	alias f = functionMixin!("vkFree"~name~"s");
132 	
133 	auto vshFrees(Ts args) {
134 		f(args[0..$-1], cast(uint) args[$-1].length, args[$-1].ptr);
135 	}
136 }
137 
138 template vshCreate(Ts...) if (Ts.length>0 && isCreateInfoType!(Ts[$-1])) {
139 	enum name = createInfoName!(Ts[$-1]);
140 	static if (is(typeof(functionMixin!("vkCreate"~name~"s"))))
141 		alias f_unenforced = functionMixin!("vkCreate"~name~"s");
142 	else
143 		alias f_unenforced = functionMixin!("vkCreate"~name);
144 	alias f = enforced!f_unenforced;
145 	alias Params = Parameters!f;
146 	
147 	////auto vshCreate(Ts args, const(VkAllocationCallbacks)* allocator, Params[$-1]* outPtr) {
148 	////	f(args, allocator, outPtr);
149 	////}
150 	////// Second to last argument allocator.
151 	////static if (is(Params[$-2] == const(VkAllocationCallbacks)*)) {
152 	////	// Given no allocator
153 	////	auto vshCreate(Ts args, Vsh!(createInfoName!(Ts[$-1]))* outPtr) {
154 	////		f(args,null,outPtr);
155 	////	}
156 	////}
157 	////// Last argument allocator.
158 	////static if (is(Params[$-1] == const(VkAllocationCallbacks)*)) {
159 	////	// Given no allocator
160 	////	auto vsh(Ts args) {
161 	////		f(args,null);
162 	////	}
163 	////}
164 	// Returning through last argument as pointer.
165 	//// static if (isPointer!(Params[$-1]) && __traits(compiles, {PointerTarget!(Params[$-1]) outPtr;})) {
166 		// Given no out ptr.
167 		auto vshCreate(Ts args, const(VkAllocationCallbacks)* allocator) {
168 			PointerTarget!(Params[$-1]) outPtr;
169 			f(args, allocator, &outPtr);
170 			return outPtr;
171 		}
172 		// Second to last argument allocator.
173 		////static if (is(Params[$-2] == const(VkAllocationCallbacks)*)) {
174 			// Given no allocator nor out ptr.
175 			auto vshCreate(Ts args) {
176 				PointerTarget!(Params[$-1]) outPtr;
177 				f(args,null,&outPtr);
178 				return outPtr;
179 			}
180 		////}
181 	////}
182 }
183 
184 template vshCreateScoped(Ts...)
185 ////if ((Ts.length==1 && is(typeof(Ts[0])==string)) || (Ts.length==2 && isCallable!(Ts[0]) && isCallable!(Ts[1])))
186 {
187 	static if (Ts.length==1 && is(typeof(Ts[0])==string)) {
188 		enum name = Ts[0];
189 		alias f_unenforced = functionMixin!("vkCreate"~Ts[0]);
190 		import std.algorithm;
191 		import std.uni;
192 		alias destroy = destroyer!(Ts[0]);
193 		///static if (!is(typeof(functionMixin!("vkDestroy"~Ts[0]))) && is(typeof(functionMixin!("vkDestroy"~Ts[0][1..$].find!isUpper))))
194 		///	alias destroy = functionMixin!("vkDestroy"~Ts[0][1..$].find!isUpper);
195 		///static if (!is(typeof(functionMixin!("vkDestroy"~Ts[0]))) && is(typeof(functionMixin!("vkDestroy"~Ts[0][1..$].find!isUpper[0..$-1]))))
196 		///	alias destroy = functionMixin!("vkDestroy"~Ts[0][1..$].find!isUpper[0..$-1]);
197 		///else
198 		///	alias destroy = functionMixin!("vkDestroy"~Ts[0]);
199 	}
200 	else static if (Ts.length==1) {
201 		alias f_unenforced = Ts[0];
202 		alias destroy = destroyer!(T[0]);
203 	}
204 	else static if (Ts.length==2 && isCallable!(Ts[0]) && isCallable!(Ts[1])) {
205 		alias f_unenforced = Ts[0];
206 		alias destroy = Ts[1];
207 	}
208 	else {
209 		static assert(false);
210 	}
211 	alias f = enforced!f_unenforced;
212 	alias Params = Parameters!f;
213 	alias T = PointerTarget!(Params[$-1]);
214 	alias ScopedT = VshScoped!T;
215 	// Returns through last argument as pointer.
216 	static assert (isPointer!(Params[$-1]));
217 	ScopedT vshCreateScoped(Parameters!f[0..$-1] args) {
218 		T outPtr;
219 		f(args, &outPtr);
220 		return ScopedT(args[0..Parameters!(ScopedT.__ctor).length-1], outPtr);
221 	}
222 	// Second to last argument allocator.
223 	static assert (is(Params[$-2] == const(VkAllocationCallbacks)*));
224 	ScopedT vshCreateScoped(Params[0..$-2] args) {
225 		T outPtr;
226 		f(args, null, &outPtr);
227 		return ScopedT(args[0..Parameters!(ScopedT.__ctor).length-1], outPtr);
228 	}
229 }
230 
231 string vshScopedDestroy(string v, string args="") {
232 	if (args.strip!="")
233 		args ~= ',';
234 	return "scope (exit) if ("~v~" != null) {
235 		import vulkanish.helpers.functions;
236 		vshDestroy("~args~v~");
237 		////import vulkanish.helpers.internal:destroyer;
238 		////import vulkanish.helpers.functions:vsh;
239 		////vsh!(destroyer!(typeof("~v~")))("~args~v~");
240 	}";
241 }
242 string vshScopedDestroyRange(string v, string args="") {
243 	if (args.strip!="")
244 		args ~= ',';
245 	return "scope (exit) {
246 		import vulkanish.helpers.functions;
247 		vshDestroyRange("~args~v~");
248 		////import vulkanish.helpers.internal:destroyer;
249 		////import vulkanish.helpers.functions:vsh;
250 		////import std.algorithm:each;
251 		////"~v~".each!(h=>vshDestroy("~args~"h));
252 		////"~v~".each!(h=>vsh!(destroyer!(typeof(h)))("~args~"h));
253 	}";
254 }
255 string vshScopedFrees(string v, string args="") {
256 	if (args.strip!="")
257 		args ~= ',';
258 	return "scope (exit) if ("~v~" != []) {
259 		import vulkanish.helpers.functions;
260 		vshFrees("~args~v~");
261 	}";
262 }
263 
264 
265 
266 
267