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;
}