module nxt.flatten_trait;

/** Is `true` iff a list of types, which are composed of ranges and non ranges,
 * share a common type after flattening the ranges (i.e. `ElementType`)
 *
 * This basically answers the question: $(I Can I combine these ranges and
 * values into a single range of a common type?).
 *
 * See_Also: `meta_ex.FlattenedRanges`
 */
template areFlatteninglyCombinable(Values...)
{
	import std.traits : CommonType;
	import nxt.meta_ex : FlattenedRanges;
	enum areFlatteninglyCombinable = !is(CommonType!(FlattenedRanges!Values) == void);
}

///
unittest {
	static assert(areFlatteninglyCombinable!(int, int, int));
	static assert(areFlatteninglyCombinable!(float[], int, char[]));
	static assert(areFlatteninglyCombinable!(string, int, int));

	// Works with string because:
	import std.traits : CommonType;
	import std.range.primitives : ElementType;

	static assert(is(CommonType!(ElementType!string, int) == uint));

	struct A
	{
	}

	static assert(!areFlatteninglyCombinable!(A, int, int));
	static assert(!areFlatteninglyCombinable!(A[], int[]));
	static assert( areFlatteninglyCombinable!(A[], A[]));
	static assert( areFlatteninglyCombinable!(A[], A[], A));
	static assert(!areFlatteninglyCombinable!(int[], A));
}