module mutils.traits;

import std.traits;

bool isForeachDelegateWithI(DG)() {
	return is(DG == delegate) && is(ReturnType!DG == int)
		&& Parameters!DG.length == 2 && isIntegral!(Parameters!(DG)[0]);
}

unittest {
	assert(isForeachDelegateWithI!(int delegate(int, double)));
	assert(isForeachDelegateWithI!(int delegate(int, double) @nogc nothrow));
	assert(!isForeachDelegateWithI!(int delegate(double, double)));
}

bool isForeachDelegateWithoutI(DG)() {
	return is(DG == delegate) && is(ReturnType!DG == int) && Parameters!DG.length == 1;
}

unittest {
	assert(isForeachDelegateWithoutI!(int delegate(int)));
	assert(isForeachDelegateWithoutI!(int delegate(size_t) @nogc nothrow));
	assert(!isForeachDelegateWithoutI!(void delegate(int)));
}

bool isForeachDelegateWithTypes(DG, Types...)() {
	return is(DG == delegate) && is(ReturnType!DG == int) && is(Parameters!DG == Types);
}

unittest {
	assert(isForeachDelegateWithTypes!(int delegate(int, int), int, int));
	assert(isForeachDelegateWithTypes!(int delegate(ref int, ref int), int, int));
	assert(!isForeachDelegateWithTypes!(int delegate(double), int, int));
}

auto assumeNoGC(T)(T t) if (isFunctionPointer!T || isDelegate!T) {
	enum attrs = functionAttributes!T | FunctionAttribute.nogc;
	return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}