import std.traits: isDynamicArray, Unqual;
import std.meta: templateNot;
alias V = Variant!(long, int, string, long[], int[]);
alias autoGetElementType = match!(
(string s) => "string", // we override the suit handler below for string
suit!(isDynamicArray, a => Unqual!(typeof(a[0])).stringof),
suit!(templateNot!isDynamicArray, a => Unqual!(typeof(a)).stringof),
);
assert(autoGetElementType(V(string.init)) == "string");
assert(autoGetElementType(V((long[]).init)) == "long");
assert(autoGetElementType(V((int[]).init)) == "int");
assert(autoGetElementType(V(long.init)) == "long");
assert(autoGetElementType(V(int.init)) == "int");
import std.traits: allSameType;
import std.meta: templateNot;
static struct Asteroid { uint size; }
static struct Spaceship { uint size; }
alias SpaceObject = Variant!(Asteroid, Spaceship);
auto errorMsg = "can't unite an asteroid with a spaceship".err;
alias unite = match!(
suit!(allSameType, (a, b) => typeof(a)(a.size + b.size)),
suit!(templateNot!allSameType, (a, b) => errorMsg),
);
auto ea = Asteroid(10);
auto es = Spaceship(1);
auto oa = SpaceObject(ea);
auto os = SpaceObject(es);
static assert(is(typeof(unite(oa, oa)) == Variant!(Err!string, Asteroid, Spaceship)));
// Asteroid-Asteroid
assert(unite(ea, ea) == Asteroid(20));
assert(unite(ea, oa) == Asteroid(20));
assert(unite(oa, ea) == Asteroid(20));
assert(unite(oa, oa) == Asteroid(20));
// Asteroid-Spaceship
assert(unite(ea, es) == errorMsg);
assert(unite(ea, os) == errorMsg);
assert(unite(oa, es) == errorMsg);
assert(unite(oa, os) == errorMsg);
// Spaceship-Asteroid
assert(unite(es, ea) == errorMsg);
assert(unite(es, oa) == errorMsg);
assert(unite(os, ea) == errorMsg);
assert(unite(os, oa) == errorMsg);
// Spaceship-Spaceship
assert(unite(es, es) == Spaceship(2));
assert(unite(es, os) == Spaceship(2));
assert(unite(os, es) == Spaceship(2));
assert(unite(os, os) == Spaceship(2));