Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.variant

This module implements a generic variant type.
struct Variant(Types...) if (Types.length);
Variant Type (aka Algebraic Type) with clever member access.
Compatible with BetterC mode.
Examples:
Test for opCmp, opEqual, toHash
import core.stdc.string: memcmp;

static struct C(ubyte payloadSize, bool isPOD, bool hasToHash = true, bool hasOpEquals = true)
{
    ubyte[payloadSize] payload;

const:

    static if (!isPOD)
    {
        this(this) {}
        ~this() {}
    }

@safe pure nothrow @nogc:


static if (hasToHash)
    size_t toHash() { return hashOf(payload); }

static if (hasOpEquals)
    auto opEquals(ref const typeof(this) rhs) @trusted { return memcmp(payload.ptr, rhs.payload.ptr, payload.length); }
    auto opCmp(ref const typeof(this) rhs) { return payload == rhs.payload; }
}

static foreach (size1; [1, 2, 4, 8, 10, 16, 20])
static foreach (size2; [1, 2, 4, 8, 10, 16, 20])
static if (size1 != size2)
static foreach (isPOD; [true, false])
static foreach (hasToHash; [true, false])
static foreach (hasOpEquals; [true, false])
{{
    alias T = Variant!(
            double,
            C!(size1, isPOD, hasToHash, hasOpEquals),
            C!(size2, isPOD, hasToHash, hasOpEquals));
    static assert (__traits(hasMember, T, "toHash") == isPOD || hasToHash);
    static assert (__traits(hasMember, T, "opEquals") == isPOD || hasOpEquals);
    static assert (__traits(hasMember, T, "opCmp"));
}}
this(typeof(null));
void opAssign(typeof(null));
const nothrow @property bool empty();
Returns:
true for the unassigned instance.
const nothrow @property uint typeId();
Returns:
zero if the instance is unassigned and type index starting with 1 otherwise.
size_t toHash();
const auto opEquals(ref const typeof(this) rhs);
const auto opCmp(ref const typeof(this) rhs);
template visit(alias visitor, bool forceAllTypes = true)
Parameters:
visitor a function name alias
forceAllTypes if true checks at compile time, that the visitor can be called for all types.
Examples:
static struct S { int a; }

Variant!(S, double) variant;
variant = 1.0;
variant.visit!((ref value, b) => value += b, false)(2);
assert (variant.get!double == 3);

alias fun = (ref value) {
    static if (is(typeof(value) == S))
        value.a += 2;
    else
       value += 2;
};

variant.visit!fun;
assert (variant.get!double == 5);

variant = S(4);
variant.visit!fun;
assert (variant.get!S.a == 6);
ref auto visit(V, Args...)(auto ref V variant, auto ref Args args)
if (is(Unqual!V : Variant!Types, Types));
template optionalVisit(alias visitor)
Parameters:
visitor a function name alias
Examples:
static struct S { int a; }

Variant!(S, double) variant;

double result = 100;

// do nothing because of variant isn't initialized
optionalVisit!((ref value) => value)(result, variant);
assert(result == 100);

variant = S(2);
// do nothing because of lambda can't compile
optionalVisit!((ref value) => value)(result, variant);
assert(result == 100);

variant = 3.0;
optionalVisit!((ref value) => value)(result, variant);
assert (result == 3);
@property bool optionalVisit(Result, V, Args...)(ref Result result, auto ref V variant, auto ref Args args)
if (is(Unqual!V : Variant!Types, Types));