Home | History | Annotate | Line # | Download | only in std
      1 // Written in the D programming language.
      2 
      3 /**
      4 This module implements a
      5 $(HTTP erdani.org/publications/cuj-04-2002.php.html,discriminated union)
      6 type (a.k.a.
      7 $(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
      8 $(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
      9 Such types are useful
     10 for type-uniform binary interfaces, interfacing with scripting
     11 languages, and comfortable exploratory programming.
     12 
     13 A $(LREF Variant) object can hold a value of any type, with very few
     14 restrictions (such as `shared` types and noncopyable types). Setting the value
     15 is as immediate as assigning to the `Variant` object. To read back the value of
     16 the appropriate type `T`, use the $(LREF get) method. To query whether a
     17 `Variant` currently holds a value of type `T`, use $(LREF peek). To fetch the
     18 exact type currently held, call $(LREF type), which returns the `TypeInfo` of
     19 the current value.
     20 
     21 In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
     22 type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
     23 types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
     24 string)) may only hold an `int` or a `string`).
     25 
     26 $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
     27 code. Instead, use $(REF SumType, std,sumtype).)
     28 
     29 Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
     30 prompting the following improvements: (1) better support for arrays; (2) support
     31 for associative arrays; (3) friendlier behavior towards the garbage collector.
     32 Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
     33 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
     34 Authors:   $(HTTP erdani.org, Andrei Alexandrescu)
     35 Source:    $(PHOBOSSRC std/variant.d)
     36 */
     37 module std.variant;
     38 
     39 import std.meta, std.traits, std.typecons;
     40 
     41 ///
     42 @system unittest
     43 {
     44     Variant a; // Must assign before use, otherwise exception ensues
     45     // Initialize with an integer; make the type int
     46     Variant b = 42;
     47     assert(b.type == typeid(int));
     48     // Peek at the value
     49     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
     50     // Automatically convert per language rules
     51     auto x = b.get!(real);
     52 
     53     // Assign any other type, including other variants
     54     a = b;
     55     a = 3.14;
     56     assert(a.type == typeid(double));
     57     // Implicit conversions work just as with built-in types
     58     assert(a < b);
     59     // Check for convertibility
     60     assert(!a.convertsTo!(int)); // double not convertible to int
     61     // Strings and all other arrays are supported
     62     a = "now I'm a string";
     63     assert(a == "now I'm a string");
     64 
     65     // can also assign arrays
     66     a = new int[42];
     67     assert(a.length == 42);
     68     a[5] = 7;
     69     assert(a[5] == 7);
     70 
     71     // Can also assign class values
     72     class Foo {}
     73     auto foo = new Foo;
     74     a = foo;
     75     assert(*a.peek!(Foo) == foo); // and full type information is preserved
     76 }
     77 
     78 /++
     79     Gives the `sizeof` the largest type given.
     80 
     81     See_Also: $(LINK https://forum.dlang.org/thread/wbpnncxepehgcswhuazl@forum.dlang.org?page=1)
     82   +/
     83 template maxSize(Ts...)
     84 {
     85     align(1) union Impl
     86     {
     87         static foreach (i, T; Ts)
     88         {
     89             static if (!is(T == void))
     90                 mixin("T _field_", i, ";");
     91         }
     92     }
     93     enum maxSize = Impl.sizeof;
     94 }
     95 
     96 ///
     97 @safe unittest
     98 {
     99     struct Cat { int a, b, c; }
    100 
    101     align(1) struct S
    102     {
    103         long l;
    104         ubyte b;
    105     }
    106 
    107     align(1) struct T
    108     {
    109         ubyte b;
    110         long l;
    111     }
    112 
    113     static assert(maxSize!(int, long) == 8);
    114     static assert(maxSize!(bool, byte) == 1);
    115     static assert(maxSize!(bool, Cat) == 12);
    116     static assert(maxSize!(char) == 1);
    117     static assert(maxSize!(char, short, ubyte) == 2);
    118     static assert(maxSize!(char, long, ubyte) == 8);
    119     import std.algorithm.comparison : max;
    120     static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof));
    121     static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof));
    122     static assert(maxSize!(int, ubyte[7]) == 7);
    123     static assert(maxSize!(int, ubyte[3]) == 4);
    124     static assert(maxSize!(int, int, ubyte[3]) == 4);
    125     static assert(maxSize!(void, int, ubyte[3]) == 4);
    126     static assert(maxSize!(void) == 1);
    127 }
    128 
    129 struct This;
    130 
    131 private alias This2Variant(V, T...) = AliasSeq!(ReplaceTypeUnless!(isAlgebraic, This, V, T));
    132 
    133 // We can't just use maxAlignment because no types might be specified
    134 // to VariantN, so handle that here and then pass along the rest.
    135 private template maxVariantAlignment(U...)
    136 if (isTypeTuple!U)
    137 {
    138     static if (U.length == 0)
    139     {
    140         import std.algorithm.comparison : max;
    141         enum maxVariantAlignment = max(real.alignof, size_t.alignof);
    142     }
    143     else
    144         enum maxVariantAlignment = maxAlignment!(U);
    145 }
    146 
    147 /**
    148  * Back-end type seldom used directly by user
    149  * code. Two commonly-used types using `VariantN` are:
    150  *
    151  * $(OL $(LI $(LREF Algebraic): A closed discriminated union with a
    152  * limited type universe (e.g., $(D Algebraic!(int, double,
    153  * string)) only accepts these three types and rejects anything
    154  * else).) $(LI $(LREF Variant): An open discriminated union allowing an
    155  * unbounded set of types. If any of the types in the `Variant`
    156  * are larger than the largest built-in type, they will automatically
    157  * be boxed. This means that even large types will only be the size
    158  * of a pointer within the `Variant`, but this also implies some
    159  * overhead. `Variant` can accommodate all primitive types and
    160  * all user-defined types.))
    161  *
    162  * Both `Algebraic` and `Variant` share $(D
    163  * VariantN)'s interface. (See their respective documentations below.)
    164  *
    165  * `VariantN` is a discriminated union type parameterized
    166  * with the largest size of the types stored (`maxDataSize`)
    167  * and with the list of allowed types (`AllowedTypes`). If
    168  * the list is empty, then any type up of size up to $(D
    169  * maxDataSize) (rounded up for alignment) can be stored in a
    170  * `VariantN` object without being boxed (types larger
    171  * than this will be boxed).
    172  *
    173  */
    174 struct VariantN(size_t maxDataSize, AllowedTypesParam...)
    175 {
    176     /**
    177     The list of allowed types. If empty, any type is allowed.
    178     */
    179     alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam);
    180 
    181 private:
    182     // Compute the largest practical size from maxDataSize
    183     struct SizeChecker
    184     {
    185         int function() fptr;
    186         ubyte[maxDataSize] data;
    187     }
    188     enum size = SizeChecker.sizeof - (int function()).sizeof;
    189 
    190     /** Tells whether a type `T` is statically _allowed for
    191      * storage inside a `VariantN` object by looking
    192      * `T` up in `AllowedTypes`.
    193      */
    194     public template allowed(T)
    195     {
    196         enum bool allowed
    197             = is(T == VariantN)
    198             ||
    199             //T.sizeof <= size &&
    200             (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0);
    201     }
    202 
    203     // Each internal operation is encoded with an identifier. See
    204     // the "handler" function below.
    205     enum OpID { getTypeInfo, get, compare, equals, testConversion, toString,
    206             index, indexAssign, catAssign, copyOut, length,
    207             apply, postblit, destruct }
    208 
    209     // state
    210     union
    211     {
    212         align(maxVariantAlignment!(AllowedTypes)) ubyte[size] store;
    213         // conservatively mark the region as pointers
    214         static if (size >= (void*).sizeof)
    215             void*[size / (void*).sizeof] p;
    216     }
    217     ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
    218         = &handler!(void);
    219 
    220     // internals
    221     // Handler for an uninitialized value
    222     static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm)
    223     {
    224         switch (selector)
    225         {
    226         case OpID.getTypeInfo:
    227             *cast(TypeInfo *) parm = typeid(A);
    228             break;
    229         case OpID.copyOut:
    230             auto target = cast(VariantN *) parm;
    231             target.fptr = &handler!(A);
    232             // no need to copy the data (it's garbage)
    233             break;
    234         case OpID.compare:
    235         case OpID.equals:
    236             auto rhs = cast(const VariantN *) parm;
    237             return rhs.peek!(A)
    238                 ? 0 // all uninitialized are equal
    239                 : ptrdiff_t.min; // uninitialized variant is not comparable otherwise
    240         case OpID.toString:
    241             string * target = cast(string*) parm;
    242             *target = "<Uninitialized VariantN>";
    243             break;
    244         case OpID.postblit:
    245         case OpID.destruct:
    246             break;
    247         case OpID.get:
    248         case OpID.testConversion:
    249         case OpID.index:
    250         case OpID.indexAssign:
    251         case OpID.catAssign:
    252         case OpID.length:
    253             throw new VariantException(
    254                 "Attempt to use an uninitialized VariantN");
    255         default: assert(false, "Invalid OpID");
    256         }
    257         return 0;
    258     }
    259 
    260     // Handler for all of a type's operations
    261     static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
    262     {
    263         import std.conv : to;
    264         static A* getPtr(void* untyped)
    265         {
    266             if (untyped)
    267             {
    268                 static if (A.sizeof <= size)
    269                     return cast(A*) untyped;
    270                 else
    271                     return *cast(A**) untyped;
    272             }
    273             return null;
    274         }
    275 
    276         static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector)
    277         {
    278             static if (is(typeof(*rhsPA == *zis)))
    279             {
    280                 enum isEmptyStructWithoutOpEquals = is(A == struct) && A.tupleof.length == 0 &&
    281                                                     !__traits(hasMember, A, "opEquals");
    282                 static if (isEmptyStructWithoutOpEquals)
    283                 {
    284                     // The check above will always succeed if A is an empty struct.
    285                     // Don't generate unreachable code as seen in
    286                     // https://issues.dlang.org/show_bug.cgi?id=21231
    287                     return 0;
    288                 }
    289                 else
    290                 {
    291                     if (*rhsPA == *zis)
    292                         return 0;
    293                     static if (is(typeof(*zis < *rhsPA)))
    294                     {
    295                         // Many types (such as any using the default Object opCmp)
    296                         // will throw on an invalid opCmp, so do it only
    297                         // if the caller requests it.
    298                         if (selector == OpID.compare)
    299                             return *zis < *rhsPA ? -1 : 1;
    300                         else
    301                             return ptrdiff_t.min;
    302                     }
    303                     else
    304                     {
    305                         // Not equal, and type does not support ordering
    306                         // comparisons.
    307                         return ptrdiff_t.min;
    308                     }
    309                 }
    310             }
    311             else
    312             {
    313                 // Type does not support comparisons at all.
    314                 return ptrdiff_t.min;
    315             }
    316         }
    317 
    318         auto zis = getPtr(pStore);
    319         // Input: TypeInfo object
    320         // Output: target points to a copy of *me, if me was not null
    321         // Returns: true iff the A can be converted to the type represented
    322         // by the incoming TypeInfo
    323         static bool tryPutting(A* src, TypeInfo targetType, void* target)
    324         {
    325             alias UA = Unqual!A;
    326             static if (isStaticArray!A && is(typeof(UA.init[0])))
    327             {
    328                 alias MutaTypes = AliasSeq!(UA, typeof(UA.init[0])[], AllImplicitConversionTargets!UA);
    329             }
    330             else
    331             {
    332                 alias MutaTypes = AliasSeq!(UA, AllImplicitConversionTargets!UA);
    333             }
    334             alias ConstTypes = staticMap!(ConstOf, MutaTypes);
    335             alias SharedTypes = staticMap!(SharedOf, MutaTypes);
    336             alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes);
    337             alias ImmuTypes  = staticMap!(ImmutableOf, MutaTypes);
    338 
    339             static if (is(A == immutable))
    340                 alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes);
    341             else static if (is(A == shared))
    342             {
    343                 static if (is(A == const))
    344                     alias AllTypes = SharedConstTypes;
    345                 else
    346                     alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes);
    347             }
    348             else
    349             {
    350                 static if (is(A == const))
    351                     alias AllTypes = ConstTypes;
    352                 else
    353                     alias AllTypes = AliasSeq!(MutaTypes, ConstTypes);
    354             }
    355 
    356             foreach (T ; AllTypes)
    357             {
    358                 if (targetType != typeid(T))
    359                     continue;
    360 
    361                 // SPECIAL NOTE: variant only will ever create a new value with
    362                 // tryPutting (effectively), and T is ALWAYS the same type of
    363                 // A, but with different modifiers (and a limited set of
    364                 // implicit targets). So this checks to see if we can construct
    365                 // a T from A, knowing that prerequisite. This handles issues
    366                 // where the type contains some constant data aside from the
    367                 // modifiers on the type itself.
    368                 static if (is(typeof(delegate T() {return *src;})) ||
    369                            is(T ==        const(U), U) ||
    370                            is(T ==       shared(U), U) ||
    371                            is(T == shared const(U), U) ||
    372                            is(T ==    immutable(U), U))
    373                 {
    374                     import core.internal.lifetime : emplaceRef;
    375 
    376                     auto zat = cast(T*) target;
    377                     if (src)
    378                     {
    379                         static if (T.sizeof > 0)
    380                             assert(target, "target must be non-null");
    381 
    382                         static if (isStaticArray!A && isDynamicArray!T)
    383                         {
    384                             auto this_ = (*src)[];
    385                             emplaceRef(*cast(Unqual!T*) zat, cast(Unqual!T) this_);
    386                         }
    387                         else
    388                         {
    389                             emplaceRef(*cast(Unqual!T*) zat, *cast(UA*) src);
    390                         }
    391                     }
    392                 }
    393                 else
    394                 {
    395                     // type T is not constructible from A
    396                     if (src)
    397                         assert(false, A.stringof);
    398                 }
    399                 return true;
    400             }
    401             return false;
    402         }
    403 
    404         switch (selector)
    405         {
    406         case OpID.getTypeInfo:
    407             *cast(TypeInfo *) parm = typeid(A);
    408             break;
    409         case OpID.copyOut:
    410             auto target = cast(VariantN *) parm;
    411             assert(target);
    412 
    413             static if (target.size < A.sizeof)
    414             {
    415                 if (target.type.tsize < A.sizeof)
    416                 {
    417                     static if (is(A == U[n], U, size_t n))
    418                     {
    419                         A* p = cast(A*)(new U[n]).ptr;
    420                     }
    421                     else
    422                     {
    423                         A* p = new A;
    424                     }
    425                     *cast(A**)&target.store = p;
    426                 }
    427             }
    428             tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store))
    429                 || assert(false);
    430             target.fptr = &handler!(A);
    431             break;
    432         case OpID.get:
    433             auto t = * cast(Tuple!(TypeInfo, void*)*) parm;
    434             return !tryPutting(zis, t[0], t[1]);
    435         case OpID.testConversion:
    436             return !tryPutting(null, *cast(TypeInfo*) parm, null);
    437         case OpID.compare:
    438         case OpID.equals:
    439             auto rhsP = cast(VariantN *) parm;
    440             auto rhsType = rhsP.type;
    441             // Are we the same?
    442             if (rhsType == typeid(A))
    443             {
    444                 // cool! Same type!
    445                 auto rhsPA = getPtr(&rhsP.store);
    446                 return compare(rhsPA, zis, selector);
    447             }
    448             else if (rhsType == typeid(void))
    449             {
    450                 // No support for ordering comparisons with
    451                 // uninitialized vars
    452                 return ptrdiff_t.min;
    453             }
    454             VariantN temp;
    455             // Do I convert to rhs?
    456             if (tryPutting(zis, rhsType, &temp.store))
    457             {
    458                 // cool, I do; temp's store contains my data in rhs's type!
    459                 // also fix up its fptr
    460                 temp.fptr = rhsP.fptr;
    461                 // now lhsWithRhsType is a full-blown VariantN of rhs's type
    462                 if (selector == OpID.compare)
    463                     return temp.opCmp(*rhsP);
    464                 else
    465                     return temp.opEquals(*rhsP) ? 0 : 1;
    466             }
    467             // Does rhs convert to zis?
    468             auto t = tuple(typeid(A), &temp.store);
    469             if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0)
    470             {
    471                 // cool! Now temp has rhs in my type!
    472                 auto rhsPA = getPtr(&temp.store);
    473                 return compare(rhsPA, zis, selector);
    474             }
    475             // Generate the function below only if the Variant's type is
    476             // comparable with 'null'
    477             static if (__traits(compiles, () => A.init == null))
    478             {
    479                 if (rhsType == typeid(null))
    480                 {
    481                     // if rhsType is typeof(null), then we're comparing with 'null'
    482                     // this takes into account 'opEquals' and 'opCmp'
    483                     // all types that can compare with null have to following properties:
    484                     // if it's 'null' then it's equal to null, otherwise it's always greater
    485                     // than 'null'
    486                     return *zis == null ? 0 : 1;
    487                 }
    488             }
    489             return ptrdiff_t.min; // dunno
    490         case OpID.toString:
    491             auto target = cast(string*) parm;
    492             static if (is(typeof(to!(string)(*zis))))
    493             {
    494                 *target = to!(string)(*zis);
    495                 break;
    496             }
    497             // TODO: The following test evaluates to true for shared objects.
    498             //       Use __traits for now until this is sorted out.
    499             // else static if (is(typeof((*zis).toString)))
    500             else static if (__traits(compiles, {(*zis).toString();}))
    501             {
    502                 *target = (*zis).toString();
    503                 break;
    504             }
    505             else
    506             {
    507                 throw new VariantException(typeid(A), typeid(string));
    508             }
    509 
    510         case OpID.index:
    511             auto result = cast(Variant*) parm;
    512             static if (isArray!(A) && !is(immutable typeof(A.init[0]) == immutable void))
    513             {
    514                 // array type; input and output are the same VariantN
    515                 size_t index = result.convertsTo!(int)
    516                     ? result.get!(int) : result.get!(size_t);
    517                 *result = (*zis)[index];
    518                 break;
    519             }
    520             else static if (isAssociativeArray!(A))
    521             {
    522                 *result = (*zis)[result.get!(typeof(A.init.keys[0]))];
    523                 break;
    524             }
    525             else
    526             {
    527                 throw new VariantException(typeid(A), result[0].type);
    528             }
    529 
    530         case OpID.indexAssign:
    531             // array type; result comes first, index comes second
    532             auto args = cast(Variant*) parm;
    533             static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0])))
    534             {
    535                 size_t index = args[1].convertsTo!(int)
    536                     ? args[1].get!(int) : args[1].get!(size_t);
    537                 (*zis)[index] = args[0].get!(typeof((*zis)[0]));
    538                 break;
    539             }
    540             else static if (isAssociativeArray!(A) && is(typeof((*zis)[A.init.keys[0]] = A.init.values[0])))
    541             {
    542                 (*zis)[args[1].get!(typeof(A.init.keys[0]))]
    543                     = args[0].get!(typeof(A.init.values[0]));
    544                 break;
    545             }
    546             else
    547             {
    548                 throw new VariantException(typeid(A), args[0].type);
    549             }
    550 
    551         case OpID.catAssign:
    552             static if (!is(immutable typeof((*zis)[0]) == immutable void) &&
    553                     is(typeof((*zis)[0])) && is(typeof(*zis ~= *zis)))
    554             {
    555                 // array type; parm is the element to append
    556                 auto arg = cast(Variant*) parm;
    557                 alias E = typeof((*zis)[0]);
    558                 if (arg[0].convertsTo!(E))
    559                 {
    560                     // append one element to the array
    561                     (*zis) ~= [ arg[0].get!(E) ];
    562                 }
    563                 else
    564                 {
    565                     // append a whole array to the array
    566                     (*zis) ~= arg[0].get!(A);
    567                 }
    568                 break;
    569             }
    570             else
    571             {
    572                 throw new VariantException(typeid(A), typeid(void[]));
    573             }
    574 
    575         case OpID.length:
    576             static if (isArray!(A) || isAssociativeArray!(A))
    577             {
    578                 return zis.length;
    579             }
    580             else
    581             {
    582                 throw new VariantException(typeid(A), typeid(void[]));
    583             }
    584 
    585         case OpID.apply:
    586             static if (!isFunctionPointer!A && !isDelegate!A)
    587             {
    588                 import std.conv : text;
    589                 import std.exception : enforce;
    590                 enforce(0, text("Cannot apply `()' to a value of type `",
    591                                 A.stringof, "'."));
    592             }
    593             else
    594             {
    595                 import std.conv : text;
    596                 import std.exception : enforce;
    597                 alias ParamTypes = Parameters!A;
    598                 auto p = cast(Variant*) parm;
    599                 auto argCount = p.get!size_t;
    600                 // To assign the tuple we need to use the unqualified version,
    601                 // otherwise we run into issues such as with const values.
    602                 // We still get the actual type from the Variant though
    603                 // to ensure that we retain const correctness.
    604                 Tuple!(staticMap!(Unqual, ParamTypes)) t;
    605                 enforce(t.length == argCount,
    606                         text("Argument count mismatch: ",
    607                              A.stringof, " expects ", t.length,
    608                              " argument(s), not ", argCount, "."));
    609                 auto variantArgs = p[1 .. argCount + 1];
    610                 foreach (i, T; ParamTypes)
    611                 {
    612                     t[i] = cast() variantArgs[i].get!T;
    613                 }
    614 
    615                 auto args = cast(Tuple!(ParamTypes))t;
    616                 static if (is(ReturnType!A == void))
    617                 {
    618                     (*zis)(args.expand);
    619                     *p = Variant.init; // void returns uninitialized Variant.
    620                 }
    621                 else
    622                 {
    623                     *p = (*zis)(args.expand);
    624                 }
    625             }
    626             break;
    627 
    628         case OpID.postblit:
    629             static if (hasElaborateCopyConstructor!A)
    630             {
    631                 zis.__xpostblit();
    632             }
    633             break;
    634 
    635         case OpID.destruct:
    636             static if (hasElaborateDestructor!A)
    637             {
    638                 zis.__xdtor();
    639             }
    640             break;
    641 
    642         default: assert(false);
    643         }
    644         return 0;
    645     }
    646 
    647 public:
    648     /** Constructs a `VariantN` value given an argument of a
    649      * generic type. Statically rejects disallowed types.
    650      */
    651 
    652     this(T)(T value)
    653     {
    654         static assert(allowed!(T), "Cannot store a " ~ T.stringof
    655             ~ " in a " ~ VariantN.stringof);
    656         opAssign(value);
    657     }
    658 
    659     /// Allows assignment from a subset algebraic type
    660     this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
    661         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
    662     {
    663         opAssign(value);
    664     }
    665 
    666     static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
    667     {
    668         this(this)
    669         {
    670             fptr(OpID.postblit, &store, null);
    671         }
    672     }
    673 
    674     static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
    675     {
    676         ~this()
    677         {
    678             // Infer the safety of the provided types
    679             static if (AllowedTypes.length)
    680             {
    681                 if (0)
    682                 {
    683                     AllowedTypes var;
    684                 }
    685             }
    686             (() @trusted => fptr(OpID.destruct, &store, null))();
    687         }
    688     }
    689 
    690     /** Assigns a `VariantN` from a generic
    691      * argument. Statically rejects disallowed types. */
    692 
    693     VariantN opAssign(T)(T rhs)
    694     {
    695         static assert(allowed!(T), "Cannot store a " ~ T.stringof
    696             ~ " in a " ~ VariantN.stringof ~ ". Valid types are "
    697                 ~ AllowedTypes.stringof);
    698 
    699         static if (is(T : VariantN))
    700         {
    701             rhs.fptr(OpID.copyOut, &rhs.store, &this);
    702         }
    703         else static if (is(T : const(VariantN)))
    704         {
    705             static assert(false,
    706                     "Assigning Variant objects from const Variant"~
    707                     " objects is currently not supported.");
    708         }
    709         else
    710         {
    711             import core.lifetime : copyEmplace;
    712 
    713             static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
    714             {
    715                 // Assignment should destruct previous value
    716                 fptr(OpID.destruct, &store, null);
    717             }
    718 
    719             static if (T.sizeof <= size)
    720                 copyEmplace(rhs, *cast(T*) &store);
    721             else
    722             {
    723                 static if (is(T == U[n], U, size_t n))
    724                     auto p = cast(T*) (new U[n]).ptr;
    725                 else
    726                     auto p = new T;
    727                 copyEmplace(rhs, *p);
    728                 *(cast(T**) &store) = p;
    729             }
    730 
    731             fptr = &handler!(T);
    732         }
    733         return this;
    734     }
    735 
    736     // Allow assignment from another variant which is a subset of this one
    737     VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
    738         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
    739     {
    740         // discover which type rhs is actually storing
    741         foreach (V; T.AllowedTypes)
    742             if (rhs.type == typeid(V))
    743                 return this = rhs.get!V;
    744         assert(0, T.AllowedTypes.stringof);
    745     }
    746 
    747 
    748     Variant opCall(P...)(auto ref P params)
    749     {
    750         Variant[P.length + 1] pack;
    751         pack[0] = P.length;
    752         foreach (i, _; params)
    753         {
    754             pack[i + 1] = params[i];
    755         }
    756         fptr(OpID.apply, &store, &pack);
    757         return pack[0];
    758     }
    759 
    760     /** Returns true if and only if the `VariantN` object
    761      * holds a valid value (has been initialized with, or assigned
    762      * from, a valid value).
    763      */
    764     @property bool hasValue() const pure nothrow
    765     {
    766         // @@@BUG@@@ in compiler, the cast shouldn't be needed
    767         return cast(typeof(&handler!(void))) fptr != &handler!(void);
    768     }
    769 
    770     ///
    771     version (StdDdoc)
    772     @system unittest
    773     {
    774         Variant a;
    775         assert(!a.hasValue);
    776         Variant b;
    777         a = b;
    778         assert(!a.hasValue); // still no value
    779         a = 5;
    780         assert(a.hasValue);
    781     }
    782 
    783     /**
    784      * If the `VariantN` object holds a value of the
    785      * $(I exact) type `T`, returns a pointer to that
    786      * value. Otherwise, returns `null`. In cases
    787      * where `T` is statically disallowed, $(D
    788      * peek) will not compile.
    789      */
    790     @property inout(T)* peek(T)() inout
    791     {
    792         static if (!is(T == void))
    793             static assert(allowed!(T), "Cannot store a " ~ T.stringof
    794                     ~ " in a " ~ VariantN.stringof);
    795         if (type != typeid(T))
    796             return null;
    797         static if (T.sizeof <= size)
    798             return cast(inout T*)&store;
    799         else
    800             return *cast(inout T**)&store;
    801     }
    802 
    803     ///
    804     version (StdDdoc)
    805     @system unittest
    806     {
    807         Variant a = 5;
    808         auto b = a.peek!(int);
    809         assert(b !is null);
    810         *b = 6;
    811         assert(a == 6);
    812     }
    813 
    814     /**
    815      * Returns the `typeid` of the currently held value.
    816      */
    817 
    818     @property TypeInfo type() const nothrow @trusted
    819     {
    820         scope(failure) assert(0);
    821 
    822         TypeInfo result;
    823         fptr(OpID.getTypeInfo, null, &result);
    824         return result;
    825     }
    826 
    827     /**
    828      * Returns `true` if and only if the `VariantN`
    829      * object holds an object implicitly convertible to type `T`.
    830      * Implicit convertibility is defined as per
    831      * $(REF_ALTTEXT AllImplicitConversionTargets, AllImplicitConversionTargets, std,traits).
    832      */
    833 
    834     @property bool convertsTo(T)() const
    835     {
    836         TypeInfo info = typeid(T);
    837         return fptr(OpID.testConversion, null, &info) == 0;
    838     }
    839 
    840     /**
    841     Returns the value stored in the `VariantN` object, either by specifying the
    842     needed type or the index in the list of allowed types. The latter overload
    843     only applies to bounded variants (e.g. $(LREF Algebraic)).
    844 
    845     Params:
    846     T = The requested type. The currently stored value must implicitly convert
    847     to the requested type, in fact `DecayStaticToDynamicArray!T`. If an
    848     implicit conversion is not possible, throws a `VariantException`.
    849     index = The index of the type among `AllowedTypesParam`, zero-based.
    850      */
    851     @property inout(T) get(T)() inout
    852     {
    853         inout(T) result = void;
    854         static if (is(T == shared))
    855             alias R = shared Unqual!T;
    856         else
    857             alias R = Unqual!T;
    858         auto buf = tuple(typeid(T), cast(R*)&result);
    859 
    860         if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
    861         {
    862             throw new VariantException(type, typeid(T));
    863         }
    864         return result;
    865     }
    866 
    867     /// Ditto
    868     @property auto get(uint index)() inout
    869     if (index < AllowedTypes.length)
    870     {
    871         foreach (i, T; AllowedTypes)
    872         {
    873             static if (index == i) return get!T;
    874         }
    875         assert(0);
    876     }
    877 
    878     /**
    879      * Returns the value stored in the `VariantN` object,
    880      * explicitly converted (coerced) to the requested type $(D
    881      * T). If `T` is a string type, the value is formatted as
    882      * a string. If the `VariantN` object is a string, a
    883      * parse of the string to type `T` is attempted. If a
    884      * conversion is not possible, throws a $(D
    885      * VariantException).
    886      */
    887 
    888     @property T coerce(T)()
    889     {
    890         import std.conv : to, text;
    891         static if (isNumeric!T || isBoolean!T)
    892         {
    893             if (convertsTo!real)
    894             {
    895                 // maybe optimize this fella; handle ints separately
    896                 return to!T(get!real);
    897             }
    898             else if (convertsTo!(const(char)[]))
    899             {
    900                 return to!T(get!(const(char)[]));
    901             }
    902             // I'm not sure why this doesn't convert to const(char),
    903             // but apparently it doesn't (probably a deeper bug).
    904             //
    905             // Until that is fixed, this quick addition keeps a common
    906             // function working. "10".coerce!int ought to work.
    907             else if (convertsTo!(immutable(char)[]))
    908             {
    909                 return to!T(get!(immutable(char)[]));
    910             }
    911             else
    912             {
    913                 import std.exception : enforce;
    914                 enforce(false, text("Type ", type, " does not convert to ",
    915                                 typeid(T)));
    916                 assert(0);
    917             }
    918         }
    919         else static if (is(T : Object))
    920         {
    921             return to!(T)(get!(Object));
    922         }
    923         else static if (isSomeString!(T))
    924         {
    925             return to!(T)(toString());
    926         }
    927         else
    928         {
    929             // Fix for bug 1649
    930             static assert(false, "unsupported type for coercion");
    931         }
    932     }
    933 
    934     /**
    935      * Formats the stored value as a string.
    936      */
    937 
    938     string toString()
    939     {
    940         string result;
    941         fptr(OpID.toString, &store, &result) == 0 || assert(false);
    942         return result;
    943     }
    944 
    945     /**
    946      * Comparison for equality used by the "==" and "!="  operators.
    947      */
    948 
    949     // returns 1 if the two are equal
    950     bool opEquals(T)(auto ref T rhs) const
    951     if (allowed!T || is(immutable T == immutable VariantN))
    952     {
    953         static if (is(immutable T == immutable VariantN))
    954             alias temp = rhs;
    955         else
    956             auto temp = VariantN(rhs);
    957         return !fptr(OpID.equals, cast(ubyte[size]*) &store,
    958                      cast(void*) &temp);
    959     }
    960 
    961     // workaround for bug 10567 fix
    962     int opCmp(ref const VariantN rhs) const
    963     {
    964         return (cast() this).opCmp!(VariantN)(cast() rhs);
    965     }
    966 
    967     /**
    968      * Ordering comparison used by the "<", "<=", ">", and ">="
    969      * operators. In case comparison is not sensible between the held
    970      * value and `rhs`, an exception is thrown.
    971      */
    972 
    973     int opCmp(T)(T rhs)
    974     if (allowed!T)  // includes T == VariantN
    975     {
    976         static if (is(T == VariantN))
    977             alias temp = rhs;
    978         else
    979             auto temp = VariantN(rhs);
    980         auto result = fptr(OpID.compare, &store, &temp);
    981         if (result == ptrdiff_t.min)
    982         {
    983             throw new VariantException(type, temp.type);
    984         }
    985 
    986         assert(result >= -1 && result <= 1);  // Should be true for opCmp.
    987         return cast(int) result;
    988     }
    989 
    990     /**
    991      * Computes the hash of the held value.
    992      */
    993 
    994     size_t toHash() const nothrow @safe
    995     {
    996         return type.getHash(&store);
    997     }
    998 
    999     private VariantN opArithmetic(T, string op)(T other)
   1000     {
   1001         static if (isInstanceOf!(.VariantN, T))
   1002         {
   1003             string tryUseType(string tp)
   1004             {
   1005                 import std.format : format;
   1006                 return q{
   1007                     static if (allowed!%1$s && T.allowed!%1$s)
   1008                         if (convertsTo!%1$s && other.convertsTo!%1$s)
   1009                             return VariantN(get!%1$s %2$s other.get!%1$s);
   1010                 }.format(tp, op);
   1011             }
   1012 
   1013             mixin(tryUseType("uint"));
   1014             mixin(tryUseType("int"));
   1015             mixin(tryUseType("ulong"));
   1016             mixin(tryUseType("long"));
   1017             mixin(tryUseType("float"));
   1018             mixin(tryUseType("double"));
   1019             mixin(tryUseType("real"));
   1020         }
   1021         else
   1022         {
   1023             static if (allowed!T)
   1024                 if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other"));
   1025             static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T)
   1026                 if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other"));
   1027             static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T)
   1028                 if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other"));
   1029             static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T)
   1030                 if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other"));
   1031             static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T)
   1032                 if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other"));
   1033             static if (allowed!float && is(T : float))
   1034                 if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other"));
   1035             static if (allowed!double && is(T : double))
   1036                 if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other"));
   1037             static if (allowed!real && is (T : real))
   1038                 if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other"));
   1039         }
   1040 
   1041         throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof);
   1042     }
   1043 
   1044     private VariantN opLogic(T, string op)(T other)
   1045     {
   1046         VariantN result;
   1047         static if (is(T == VariantN))
   1048         {
   1049             if (convertsTo!(uint) && other.convertsTo!(uint))
   1050                 result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
   1051             else if (convertsTo!(int) && other.convertsTo!(int))
   1052                 result = mixin("get!(int) " ~ op ~ " other.get!(int)");
   1053             else if (convertsTo!(ulong) && other.convertsTo!(ulong))
   1054                 result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
   1055             else
   1056                 result = mixin("get!(long) " ~ op ~ " other.get!(long)");
   1057         }
   1058         else
   1059         {
   1060             if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
   1061                 result = mixin("get!(uint) " ~ op ~ " other");
   1062             else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
   1063                 result = mixin("get!(int) " ~ op ~ " other");
   1064             else if (is(typeof(T.max) : ulong) && T.min == 0
   1065                      && convertsTo!(ulong))
   1066                 result = mixin("get!(ulong) " ~ op ~ " other");
   1067             else
   1068                 result = mixin("get!(long) " ~ op ~ " other");
   1069         }
   1070         return result;
   1071     }
   1072 
   1073     /**
   1074      * Arithmetic between `VariantN` objects and numeric
   1075      * values. All arithmetic operations return a `VariantN`
   1076      * object typed depending on the types of both values
   1077      * involved. The conversion rules mimic D's built-in rules for
   1078      * arithmetic conversions.
   1079      */
   1080     VariantN opBinary(string op, T)(T rhs)
   1081     if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "^^" || op == "%") &&
   1082         is(typeof(opArithmetic!(T, op)(rhs))))
   1083     { return opArithmetic!(T, op)(rhs); }
   1084     ///ditto
   1085     VariantN opBinary(string op, T)(T rhs)
   1086     if ((op == "&" || op == "|" || op == "^" || op == ">>" || op == "<<" || op == ">>>") &&
   1087         is(typeof(opLogic!(T, op)(rhs))))
   1088     { return opLogic!(T, op)(rhs); }
   1089     ///ditto
   1090     VariantN opBinaryRight(string op, T)(T lhs)
   1091     if ((op == "+" || op == "*") &&
   1092         is(typeof(opArithmetic!(T, op)(lhs))))
   1093     { return opArithmetic!(T, op)(lhs); }
   1094     ///ditto
   1095     VariantN opBinaryRight(string op, T)(T lhs)
   1096     if ((op == "&" || op == "|" || op == "^") &&
   1097         is(typeof(opLogic!(T, op)(lhs))))
   1098     { return opLogic!(T, op)(lhs); }
   1099     ///ditto
   1100     VariantN opBinary(string op, T)(T rhs)
   1101         if (op == "~")
   1102     {
   1103         auto temp = this;
   1104         temp ~= rhs;
   1105         return temp;
   1106     }
   1107     // ///ditto
   1108     // VariantN opBinaryRight(string op, T)(T rhs)
   1109     //     if (op == "~")
   1110     // {
   1111     //     VariantN temp = rhs;
   1112     //     temp ~= this;
   1113     //     return temp;
   1114     // }
   1115 
   1116     ///ditto
   1117     VariantN opOpAssign(string op, T)(T rhs)
   1118     {
   1119         static if (op != "~")
   1120         {
   1121             mixin("return this = this" ~ op ~ "rhs;");
   1122         }
   1123         else
   1124         {
   1125             auto toAppend = Variant(rhs);
   1126             fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
   1127             return this;
   1128         }
   1129     }
   1130 
   1131     /**
   1132      * Array and associative array operations. If a $(D
   1133      * VariantN) contains an (associative) array, it can be indexed
   1134      * into. Otherwise, an exception is thrown.
   1135      */
   1136     inout(Variant) opIndex(K)(K i) inout
   1137     {
   1138         auto result = Variant(i);
   1139         fptr(OpID.index, cast(ubyte[size]*) &store, &result) == 0 || assert(false);
   1140         return result;
   1141     }
   1142 
   1143     ///
   1144     version (StdDdoc)
   1145     @system unittest
   1146     {
   1147         Variant a = new int[10];
   1148         a[5] = 42;
   1149         assert(a[5] == 42);
   1150         a[5] += 8;
   1151         assert(a[5] == 50);
   1152 
   1153         int[int] hash = [ 42:24 ];
   1154         a = hash;
   1155         assert(a[42] == 24);
   1156         a[42] /= 2;
   1157         assert(a[42] == 12);
   1158     }
   1159 
   1160     /// ditto
   1161     Variant opIndexAssign(T, N)(T value, N i)
   1162     {
   1163         static if (AllowedTypes.length && !isInstanceOf!(.VariantN, T))
   1164         {
   1165             enum canAssign(U) = __traits(compiles, (U u){ u[i] = value; });
   1166             static assert(anySatisfy!(canAssign, AllowedTypes),
   1167                 "Cannot assign " ~ T.stringof ~ " to " ~ VariantN.stringof ~
   1168                 " indexed with " ~ N.stringof);
   1169         }
   1170         Variant[2] args = [ Variant(value), Variant(i) ];
   1171         fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
   1172         return args[0];
   1173     }
   1174 
   1175     /// ditto
   1176     Variant opIndexOpAssign(string op, T, N)(T value, N i)
   1177     {
   1178         return opIndexAssign(mixin(`opIndex(i)` ~ op ~ `value`), i);
   1179     }
   1180 
   1181     /** If the `VariantN` contains an (associative) array,
   1182      * returns the _length of that array. Otherwise, throws an
   1183      * exception.
   1184      */
   1185     @property size_t length()
   1186     {
   1187         return cast(size_t) fptr(OpID.length, &store, null);
   1188     }
   1189 
   1190     /**
   1191        If the `VariantN` contains an array, applies `dg` to each
   1192        element of the array in turn. Otherwise, throws an exception.
   1193      */
   1194     int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))
   1195     {
   1196         alias A = Parameters!(Delegate)[0];
   1197         if (type == typeid(A[]))
   1198         {
   1199             auto arr = get!(A[]);
   1200             foreach (ref e; arr)
   1201             {
   1202                 if (dg(e)) return 1;
   1203             }
   1204         }
   1205         else static if (is(A == VariantN))
   1206         {
   1207             foreach (i; 0 .. length)
   1208             {
   1209                 // @@@TODO@@@: find a better way to not confuse
   1210                 // clients who think they change values stored in the
   1211                 // Variant when in fact they are only changing tmp.
   1212                 auto tmp = this[i];
   1213                 debug scope(exit) assert(tmp == this[i]);
   1214                 if (dg(tmp)) return 1;
   1215             }
   1216         }
   1217         else
   1218         {
   1219             import std.conv : text;
   1220             import std.exception : enforce;
   1221             enforce(false, text("Variant type ", type,
   1222                             " not iterable with values of type ",
   1223                             A.stringof));
   1224         }
   1225         return 0;
   1226     }
   1227 }
   1228 
   1229 ///
   1230 @system unittest
   1231 {
   1232     alias Var = VariantN!(maxSize!(int, double, string));
   1233 
   1234     Var a; // Must assign before use, otherwise exception ensues
   1235     // Initialize with an integer; make the type int
   1236     Var b = 42;
   1237     assert(b.type == typeid(int));
   1238     // Peek at the value
   1239     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
   1240     // Automatically convert per language rules
   1241     auto x = b.get!(real);
   1242 
   1243     // Assign any other type, including other variants
   1244     a = b;
   1245     a = 3.14;
   1246     assert(a.type == typeid(double));
   1247     // Implicit conversions work just as with built-in types
   1248     assert(a < b);
   1249     // Check for convertibility
   1250     assert(!a.convertsTo!(int)); // double not convertible to int
   1251     // Strings and all other arrays are supported
   1252     a = "now I'm a string";
   1253     assert(a == "now I'm a string");
   1254 }
   1255 
   1256 /// can also assign arrays
   1257 @system unittest
   1258 {
   1259     alias Var = VariantN!(maxSize!(int[]));
   1260 
   1261     Var a = new int[42];
   1262     assert(a.length == 42);
   1263     a[5] = 7;
   1264     assert(a[5] == 7);
   1265 }
   1266 
   1267 @safe unittest
   1268 {
   1269     alias V = VariantN!24;
   1270     const alignMask = V.alignof - 1;
   1271     assert(V.sizeof == ((24 + (void*).sizeof + alignMask) & ~alignMask));
   1272 }
   1273 
   1274 /// Can also assign class values
   1275 @system unittest
   1276 {
   1277     alias Var = VariantN!(maxSize!(int*)); // classes are pointers
   1278     Var a;
   1279 
   1280     class Foo {}
   1281     auto foo = new Foo;
   1282     a = foo;
   1283     assert(*a.peek!(Foo) == foo); // and full type information is preserved
   1284 }
   1285 
   1286 @system unittest
   1287 {
   1288     import std.conv : to;
   1289     Variant v;
   1290     int foo() { return 42; }
   1291     v = &foo;
   1292     assert(v() == 42);
   1293 
   1294     static int bar(string s) { return to!int(s); }
   1295     v = &bar;
   1296     assert(v("43") == 43);
   1297 }
   1298 
   1299 @system unittest
   1300 {
   1301     int[int] hash = [ 42:24 ];
   1302     Variant v = hash;
   1303     assert(v[42] == 24);
   1304     v[42] = 5;
   1305     assert(v[42] == 5);
   1306 }
   1307 
   1308 // opIndex with static arrays, https://issues.dlang.org/show_bug.cgi?id=12771
   1309 @system unittest
   1310 {
   1311     int[4] elements = [0, 1, 2, 3];
   1312     Variant v = elements;
   1313     assert(v == elements);
   1314     assert(v[2] == 2);
   1315     assert(v[3] == 3);
   1316     v[2] = 6;
   1317     assert(v[2] == 6);
   1318     assert(v != elements);
   1319 }
   1320 
   1321 @system unittest
   1322 {
   1323     import std.exception : assertThrown;
   1324     Algebraic!(int[]) v = [2, 2];
   1325 
   1326     assert(v == [2, 2]);
   1327     v[0] = 1;
   1328     assert(v[0] == 1);
   1329     assert(v != [2, 2]);
   1330 
   1331     // opIndexAssign from Variant
   1332     v[1] = v[0];
   1333     assert(v[1] == 1);
   1334 
   1335     static assert(!__traits(compiles, (v[1] = null)));
   1336     assertThrown!VariantException(v[1] = Variant(null));
   1337 }
   1338 
   1339 // https://issues.dlang.org/show_bug.cgi?id=10879
   1340 @system unittest
   1341 {
   1342     int[10] arr = [1,2,3,4,5,6,7,8,9,10];
   1343     Variant v1 = arr;
   1344     Variant v2;
   1345     v2 = arr;
   1346     assert(v1 == arr);
   1347     assert(v2 == arr);
   1348     foreach (i, e; arr)
   1349     {
   1350         assert(v1[i] == e);
   1351         assert(v2[i] == e);
   1352     }
   1353     static struct LargeStruct
   1354     {
   1355         int[100] data;
   1356     }
   1357     LargeStruct ls;
   1358     ls.data[] = 4;
   1359     v1 = ls;
   1360     Variant v3 = ls;
   1361     assert(v1 == ls);
   1362     assert(v3 == ls);
   1363 }
   1364 
   1365 // https://issues.dlang.org/show_bug.cgi?id=8195
   1366 @system unittest
   1367 {
   1368     struct S
   1369     {
   1370         int a;
   1371         long b;
   1372         string c;
   1373         real d = 0.0;
   1374         bool e;
   1375     }
   1376 
   1377     static assert(S.sizeof >= Variant.sizeof);
   1378     alias Types = AliasSeq!(string, int, S);
   1379     alias MyVariant = VariantN!(maxSize!Types, Types);
   1380 
   1381     auto v = MyVariant(S.init);
   1382     assert(v == S.init);
   1383 }
   1384 
   1385 // https://issues.dlang.org/show_bug.cgi?id=10961
   1386 @system unittest
   1387 {
   1388     // Primarily test that we can assign a void[] to a Variant.
   1389     void[] elements = cast(void[])[1, 2, 3];
   1390     Variant v = elements;
   1391     void[] returned = v.get!(void[]);
   1392     assert(returned == elements);
   1393 }
   1394 
   1395 // https://issues.dlang.org/show_bug.cgi?id=13352
   1396 @system unittest
   1397 {
   1398     alias TP = Algebraic!(long);
   1399     auto a = TP(1L);
   1400     auto b = TP(2L);
   1401     assert(!TP.allowed!ulong);
   1402     assert(a + b == 3L);
   1403     assert(a + 2 == 3L);
   1404     assert(1 + b == 3L);
   1405 
   1406     alias TP2 = Algebraic!(long, string);
   1407     auto c = TP2(3L);
   1408     assert(a + c == 4L);
   1409 }
   1410 
   1411 // https://issues.dlang.org/show_bug.cgi?id=13354
   1412 @system unittest
   1413 {
   1414     alias A = Algebraic!(string[]);
   1415     A a = ["a", "b"];
   1416     assert(a[0] == "a");
   1417     assert(a[1] == "b");
   1418     a[1] = "c";
   1419     assert(a[1] == "c");
   1420 
   1421     alias AA = Algebraic!(int[string]);
   1422     AA aa = ["a": 1, "b": 2];
   1423     assert(aa["a"] == 1);
   1424     assert(aa["b"] == 2);
   1425     aa["b"] = 3;
   1426     assert(aa["b"] == 3);
   1427 }
   1428 
   1429 // https://issues.dlang.org/show_bug.cgi?id=14198
   1430 @system unittest
   1431 {
   1432     Variant a = true;
   1433     assert(a.type == typeid(bool));
   1434 }
   1435 
   1436 // https://issues.dlang.org/show_bug.cgi?id=14233
   1437 @system unittest
   1438 {
   1439     alias Atom = Algebraic!(string, This[]);
   1440 
   1441     Atom[] values = [];
   1442     auto a = Atom(values);
   1443 }
   1444 
   1445 pure nothrow @nogc
   1446 @system unittest
   1447 {
   1448     Algebraic!(int, double) a;
   1449     a = 100;
   1450     a = 1.0;
   1451 }
   1452 
   1453 // https://issues.dlang.org/show_bug.cgi?id=14457
   1454 @system unittest
   1455 {
   1456     alias A = Algebraic!(int, float, double);
   1457     alias B = Algebraic!(int, float);
   1458 
   1459     A a = 1;
   1460     B b = 6f;
   1461     a = b;
   1462 
   1463     assert(a.type == typeid(float));
   1464     assert(a.get!float == 6f);
   1465 }
   1466 
   1467 // https://issues.dlang.org/show_bug.cgi?id=14585
   1468 @system unittest
   1469 {
   1470     static struct S
   1471     {
   1472         int x = 42;
   1473         ~this() {assert(x == 42);}
   1474     }
   1475     Variant(S()).get!S;
   1476 }
   1477 
   1478 // https://issues.dlang.org/show_bug.cgi?id=14586
   1479 @system unittest
   1480 {
   1481     const Variant v = new immutable Object;
   1482     v.get!(immutable Object);
   1483 }
   1484 
   1485 @system unittest
   1486 {
   1487     static struct S
   1488     {
   1489         T opCast(T)() {assert(false);}
   1490     }
   1491     Variant v = S();
   1492     v.get!S;
   1493 }
   1494 
   1495 // https://issues.dlang.org/show_bug.cgi?id=13262
   1496 @system unittest
   1497 {
   1498     static void fun(T)(Variant v){
   1499         T x;
   1500         v = x;
   1501         auto r = v.get!(T);
   1502     }
   1503     Variant v;
   1504     fun!(shared(int))(v);
   1505     fun!(shared(int)[])(v);
   1506 
   1507     static struct S1
   1508     {
   1509         int c;
   1510         string a;
   1511     }
   1512 
   1513     static struct S2
   1514     {
   1515         string a;
   1516         shared int[] b;
   1517     }
   1518 
   1519     static struct S3
   1520     {
   1521         string a;
   1522         shared int[] b;
   1523         int c;
   1524     }
   1525 
   1526     fun!(S1)(v);
   1527     fun!(shared(S1))(v);
   1528     fun!(S2)(v);
   1529     fun!(shared(S2))(v);
   1530     fun!(S3)(v);
   1531     fun!(shared(S3))(v);
   1532 
   1533     // ensure structs that are shared, but don't have shared postblits
   1534     // can't be used.
   1535     static struct S4
   1536     {
   1537         int x;
   1538         this(this) {x = 0;}
   1539     }
   1540 
   1541     fun!(S4)(v);
   1542     static assert(!is(typeof(fun!(shared(S4))(v))));
   1543 }
   1544 
   1545 @safe unittest
   1546 {
   1547     Algebraic!(int) x;
   1548 
   1549     static struct SafeS
   1550     {
   1551         @safe ~this() {}
   1552     }
   1553 
   1554     Algebraic!(SafeS) y;
   1555 }
   1556 
   1557 // https://issues.dlang.org/show_bug.cgi?id=19986
   1558 @system unittest
   1559 {
   1560     VariantN!32 v;
   1561     v = const(ubyte[33]).init;
   1562 
   1563     struct S
   1564     {
   1565         ubyte[33] s;
   1566     }
   1567 
   1568     VariantN!32 v2;
   1569     v2 = const(S).init;
   1570 }
   1571 
   1572 // https://issues.dlang.org/show_bug.cgi?id=21021
   1573 @system unittest
   1574 {
   1575     static struct S
   1576     {
   1577         int h;
   1578         int[5] array;
   1579         alias h this;
   1580     }
   1581 
   1582     S msg;
   1583     msg.array[] = 3;
   1584     Variant a = msg;
   1585     auto other = a.get!S;
   1586     assert(msg.array[0] == 3);
   1587     assert(other.array[0] == 3);
   1588 }
   1589 
   1590 // https://issues.dlang.org/show_bug.cgi?id=21231
   1591 // Compatibility with -preview=fieldwise
   1592 @system unittest
   1593 {
   1594     static struct Empty
   1595     {
   1596         bool opCmp(const scope ref Empty) const
   1597         { return false; }
   1598     }
   1599 
   1600     Empty a, b;
   1601     assert(a == b);
   1602     assert(!(a < b));
   1603 
   1604     VariantN!(4, Empty) v = a;
   1605     assert(v == b);
   1606     assert(!(v < b));
   1607 }
   1608 
   1609 // Compatibility with -preview=fieldwise
   1610 @system unittest
   1611 {
   1612     static struct Empty
   1613     {
   1614         bool opEquals(const scope ref Empty) const
   1615         { return false; }
   1616     }
   1617 
   1618     Empty a, b;
   1619     assert(a != b);
   1620 
   1621     VariantN!(4, Empty) v = a;
   1622     assert(v != b);
   1623 }
   1624 
   1625 // https://issues.dlang.org/show_bug.cgi?id=22647
   1626 // Can compare with 'null'
   1627 @system unittest
   1628 {
   1629     static struct Bar
   1630     {
   1631         int* ptr;
   1632         alias ptr this;
   1633     }
   1634 
   1635     static class Foo {}
   1636     int* iptr;
   1637     int[] arr;
   1638 
   1639     Variant v = Foo.init; // 'null'
   1640     assert(v != null); // can only compare objects with 'null' by using 'is'
   1641 
   1642     v = iptr;
   1643     assert(v == null); // pointers can be compared with 'null'
   1644 
   1645     v = arr;
   1646     assert(v == null); // arrays can be compared with 'null'
   1647 
   1648     v = "";
   1649     assert(v == null); // strings are arrays, an empty string is considered 'null'
   1650 
   1651     v = Bar.init;
   1652     assert(v == null); // works with alias this
   1653 
   1654     v = [3];
   1655     assert(v != null);
   1656     assert(v > null);
   1657     assert(v >= null);
   1658     assert(!(v < null));
   1659 }
   1660 
   1661 /**
   1662 _Algebraic data type restricted to a closed set of possible
   1663 types. It's an alias for $(LREF VariantN) with an
   1664 appropriately-constructed maximum size. `Algebraic` is
   1665 useful when it is desirable to restrict what a discriminated type
   1666 could hold to the end of defining simpler and more efficient
   1667 manipulation.
   1668 
   1669 $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
   1670 code. Instead, use $(REF SumType, std,sumtype).)
   1671 */
   1672 template Algebraic(T...)
   1673 {
   1674     alias Algebraic = VariantN!(maxSize!T, T);
   1675 }
   1676 
   1677 ///
   1678 @system unittest
   1679 {
   1680     auto v = Algebraic!(int, double, string)(5);
   1681     assert(v.peek!(int));
   1682     v = 3.14;
   1683     assert(v.peek!(double));
   1684     // auto x = v.peek!(long); // won't compile, type long not allowed
   1685     // v = '1'; // won't compile, type char not allowed
   1686 }
   1687 
   1688 /**
   1689 $(H4 Self-Referential Types)
   1690 
   1691 A useful and popular use of algebraic data structures is for defining $(LUCKY
   1692 self-referential data structures), i.e. structures that embed references to
   1693 values of their own type within.
   1694 
   1695 This is achieved with `Algebraic` by using `This` as a placeholder whenever a
   1696 reference to the type being defined is needed. The `Algebraic` instantiation
   1697 will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
   1698 alpha renaming) on its constituent types, replacing `This`
   1699 with the self-referenced type. The structure of the type involving `This` may
   1700 be arbitrarily complex.
   1701 */
   1702 @system unittest
   1703 {
   1704     import std.typecons : Tuple, tuple;
   1705 
   1706     // A tree is either a leaf or a branch of two other trees
   1707     alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
   1708     Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
   1709     Tree!int* right = tree.get!1[1];
   1710     assert(*right == 43);
   1711 
   1712     // An object is a double, a string, or a hash of objects
   1713     alias Obj = Algebraic!(double, string, This[string]);
   1714     Obj obj = "hello";
   1715     assert(obj.get!1 == "hello");
   1716     obj = 42.0;
   1717     assert(obj.get!0 == 42);
   1718     obj = ["customer": Obj("John"), "paid": Obj(23.95)];
   1719     assert(obj.get!2["customer"] == "John");
   1720 }
   1721 
   1722 private struct FakeComplexReal
   1723 {
   1724     real re, im;
   1725 }
   1726 
   1727 /**
   1728 Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
   1729 `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
   1730 to hold all of D's predefined types unboxed, including all numeric types,
   1731 pointers, delegates, and class references.  You may want to use
   1732 `VariantN` directly with a different maximum size either for
   1733 storing larger types unboxed, or for saving memory.
   1734  */
   1735 alias Variant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()));
   1736 
   1737 ///
   1738 @system unittest
   1739 {
   1740     Variant a; // Must assign before use, otherwise exception ensues
   1741     // Initialize with an integer; make the type int
   1742     Variant b = 42;
   1743     assert(b.type == typeid(int));
   1744     // Peek at the value
   1745     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
   1746     // Automatically convert per language rules
   1747     auto x = b.get!(real);
   1748 
   1749     // Assign any other type, including other variants
   1750     a = b;
   1751     a = 3.14;
   1752     assert(a.type == typeid(double));
   1753     // Implicit conversions work just as with built-in types
   1754     assert(a < b);
   1755     // Check for convertibility
   1756     assert(!a.convertsTo!(int)); // double not convertible to int
   1757     // Strings and all other arrays are supported
   1758     a = "now I'm a string";
   1759     assert(a == "now I'm a string");
   1760 }
   1761 
   1762 /// can also assign arrays
   1763 @system unittest
   1764 {
   1765     Variant a = new int[42];
   1766     assert(a.length == 42);
   1767     a[5] = 7;
   1768     assert(a[5] == 7);
   1769 }
   1770 
   1771 /// Can also assign class values
   1772 @system unittest
   1773 {
   1774     Variant a;
   1775 
   1776     class Foo {}
   1777     auto foo = new Foo;
   1778     a = foo;
   1779     assert(*a.peek!(Foo) == foo); // and full type information is preserved
   1780 }
   1781 
   1782 /**
   1783  * Returns an array of variants constructed from `args`.
   1784  *
   1785  * This is by design. During construction the `Variant` needs
   1786  * static type information about the type being held, so as to store a
   1787  * pointer to function for fast retrieval.
   1788  */
   1789 Variant[] variantArray(T...)(T args)
   1790 {
   1791     Variant[] result;
   1792     foreach (arg; args)
   1793     {
   1794         result ~= Variant(arg);
   1795     }
   1796     return result;
   1797 }
   1798 
   1799 ///
   1800 @system unittest
   1801 {
   1802     auto a = variantArray(1, 3.14, "Hi!");
   1803     assert(a[1] == 3.14);
   1804     auto b = Variant(a); // variant array as variant
   1805     assert(b[1] == 3.14);
   1806 }
   1807 
   1808 /**
   1809  * Thrown in three cases:
   1810  *
   1811  * $(OL $(LI An uninitialized `Variant` is used in any way except
   1812  * assignment and `hasValue`;) $(LI A `get` or
   1813  * `coerce` is attempted with an incompatible target type;)
   1814  * $(LI A comparison between `Variant` objects of
   1815  * incompatible types is attempted.))
   1816  *
   1817  */
   1818 
   1819 // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
   1820 static class VariantException : Exception
   1821 {
   1822     /// The source type in the conversion or comparison
   1823     TypeInfo source;
   1824     /// The target type in the conversion or comparison
   1825     TypeInfo target;
   1826     this(string s)
   1827     {
   1828         super(s);
   1829     }
   1830     this(TypeInfo source, TypeInfo target)
   1831     {
   1832         super("Variant: attempting to use incompatible types "
   1833                             ~ source.toString()
   1834                             ~ " and " ~ target.toString());
   1835         this.source = source;
   1836         this.target = target;
   1837     }
   1838 }
   1839 
   1840 ///
   1841 @system unittest
   1842 {
   1843     import std.exception : assertThrown;
   1844 
   1845     Variant v;
   1846 
   1847     // uninitialized use
   1848     assertThrown!VariantException(v + 1);
   1849     assertThrown!VariantException(v.length);
   1850 
   1851     // .get with an incompatible target type
   1852     assertThrown!VariantException(Variant("a").get!int);
   1853 
   1854     // comparison between incompatible types
   1855     assertThrown!VariantException(Variant(3) < Variant("a"));
   1856 }
   1857 
   1858 @system unittest
   1859 {
   1860     alias W1 = This2Variant!(char, int, This[int]);
   1861     alias W2 = AliasSeq!(int, char[int]);
   1862     static assert(is(W1 == W2));
   1863 
   1864     alias var_t = Algebraic!(void, string);
   1865     var_t foo = "quux";
   1866 }
   1867 
   1868 @system unittest
   1869 {
   1870      alias A = Algebraic!(real, This[], This[int], This[This]);
   1871      A v1, v2, v3;
   1872      v2 = 5.0L;
   1873      v3 = 42.0L;
   1874      //v1 = [ v2 ][];
   1875       auto v = v1.peek!(A[]);
   1876      //writeln(v[0]);
   1877      v1 = [ 9 : v3 ];
   1878      //writeln(v1);
   1879      v1 = [ v3 : v3 ];
   1880      //writeln(v1);
   1881 }
   1882 
   1883 @system unittest
   1884 {
   1885     import std.conv : ConvException;
   1886     import std.exception : assertThrown, collectException;
   1887     // try it with an oddly small size
   1888     VariantN!(1) test;
   1889     assert(test.size > 1);
   1890 
   1891     // variantArray tests
   1892     auto heterogeneous = variantArray(1, 4.5, "hi");
   1893     assert(heterogeneous.length == 3);
   1894     auto variantArrayAsVariant = Variant(heterogeneous);
   1895     assert(variantArrayAsVariant[0] == 1);
   1896     assert(variantArrayAsVariant.length == 3);
   1897 
   1898     // array tests
   1899     auto arr = Variant([1.2].dup);
   1900     auto e = arr[0];
   1901     assert(e == 1.2);
   1902     arr[0] = 2.0;
   1903     assert(arr[0] == 2);
   1904     arr ~= 4.5;
   1905     assert(arr[1] == 4.5);
   1906 
   1907     // general tests
   1908     Variant a;
   1909     auto b = Variant(5);
   1910     assert(!b.peek!(real) && b.peek!(int));
   1911     // assign
   1912     a = *b.peek!(int);
   1913     // comparison
   1914     assert(a == b, a.type.toString() ~ " " ~ b.type.toString());
   1915     auto c = Variant("this is a string");
   1916     assert(a != c);
   1917     // comparison via implicit conversions
   1918     a = 42; b = 42.0; assert(a == b);
   1919 
   1920     // try failing conversions
   1921     bool failed = false;
   1922     try
   1923     {
   1924         auto d = c.get!(int);
   1925     }
   1926     catch (Exception e)
   1927     {
   1928         //writeln(stderr, e.toString);
   1929         failed = true;
   1930     }
   1931     assert(failed); // :o)
   1932 
   1933     // toString tests
   1934     a = Variant(42); assert(a.toString() == "42");
   1935     a = Variant(42.22); assert(a.toString() == "42.22");
   1936 
   1937     // coerce tests
   1938     a = Variant(42.22); assert(a.coerce!(int) == 42);
   1939     a = cast(short) 5; assert(a.coerce!(double) == 5);
   1940     a = Variant("10"); assert(a.coerce!int == 10);
   1941 
   1942     a = Variant(1);
   1943     assert(a.coerce!bool);
   1944     a = Variant(0);
   1945     assert(!a.coerce!bool);
   1946 
   1947     a = Variant(1.0);
   1948     assert(a.coerce!bool);
   1949     a = Variant(0.0);
   1950     assert(!a.coerce!bool);
   1951     a = Variant(float.init);
   1952     assertThrown!ConvException(a.coerce!bool);
   1953 
   1954     a = Variant("true");
   1955     assert(a.coerce!bool);
   1956     a = Variant("false");
   1957     assert(!a.coerce!bool);
   1958     a = Variant("");
   1959     assertThrown!ConvException(a.coerce!bool);
   1960 
   1961     // Object tests
   1962     class B1 {}
   1963     class B2 : B1 {}
   1964     a = new B2;
   1965     assert(a.coerce!(B1) !is null);
   1966     a = new B1;
   1967     assert(collectException(a.coerce!(B2) is null));
   1968     a = cast(Object) new B2; // lose static type info; should still work
   1969     assert(a.coerce!(B2) !is null);
   1970 
   1971 //     struct Big { int a[45]; }
   1972 //     a = Big.init;
   1973 
   1974     // hash
   1975     assert(a.toHash() != 0);
   1976 }
   1977 
   1978 // tests adapted from
   1979 // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601
   1980 @system unittest
   1981 {
   1982     Variant v;
   1983 
   1984     assert(!v.hasValue);
   1985     v = 42;
   1986     assert( v.peek!(int) );
   1987     assert( v.convertsTo!(long) );
   1988     assert( v.get!(int) == 42 );
   1989     assert( v.get!(long) == 42L );
   1990     assert( v.get!(ulong) == 42uL );
   1991 
   1992     v = "Hello, World!";
   1993     assert( v.peek!(string) );
   1994 
   1995     assert( v.get!(string) == "Hello, World!" );
   1996     assert(!is(char[] : wchar[]));
   1997     assert( !v.convertsTo!(wchar[]) );
   1998     assert( v.get!(string) == "Hello, World!" );
   1999 
   2000     // Literal arrays are dynamically-typed
   2001     v = cast(int[4]) [1,2,3,4];
   2002     assert( v.peek!(int[4]) );
   2003     assert( v.get!(int[4]) == [1,2,3,4] );
   2004 
   2005     {
   2006          v = [1,2,3,4,5];
   2007          assert( v.peek!(int[]) );
   2008          assert( v.get!(int[]) == [1,2,3,4,5] );
   2009     }
   2010 
   2011     v = 3.1413;
   2012     assert( v.peek!(double) );
   2013     assert( v.convertsTo!(real) );
   2014     //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT
   2015     assert( v.convertsTo!(float) );
   2016     assert( *v.peek!(double) == 3.1413 );
   2017 
   2018     auto u = Variant(v);
   2019     assert( u.peek!(double) );
   2020     assert( *u.peek!(double) == 3.1413 );
   2021 
   2022     // operators
   2023     v = 38;
   2024     assert( v + 4 == 42 );
   2025     assert( 4 + v == 42 );
   2026     assert( v - 4 == 34 );
   2027     assert( Variant(4) - v == -34 );
   2028     assert( v * 2 == 76 );
   2029     assert( 2 * v == 76 );
   2030     assert( v / 2 == 19 );
   2031     assert( Variant(2) / v == 0 );
   2032     assert( v % 2 == 0 );
   2033     assert( Variant(2) % v == 2 );
   2034     assert( (v & 6) == 6 );
   2035     assert( (6 & v) == 6 );
   2036     assert( (v | 9) == 47 );
   2037     assert( (9 | v) == 47 );
   2038     assert( (v ^ 5) == 35 );
   2039     assert( (5 ^ v) == 35 );
   2040     assert( v << 1 == 76 );
   2041     assert( Variant(1) << Variant(2) == 4 );
   2042     assert( v >> 1 == 19 );
   2043     assert( Variant(4) >> Variant(2) == 1 );
   2044     assert( Variant("abc") ~ "def" == "abcdef" );
   2045     assert( Variant("abc") ~ Variant("def") == "abcdef" );
   2046 
   2047     v = 38;
   2048     v += 4;
   2049     assert( v == 42 );
   2050     v = 38; v -= 4; assert( v == 34 );
   2051     v = 38; v *= 2; assert( v == 76 );
   2052     v = 38; v /= 2; assert( v == 19 );
   2053     v = 38; v %= 2; assert( v == 0 );
   2054     v = 38; v &= 6; assert( v == 6 );
   2055     v = 38; v |= 9; assert( v == 47 );
   2056     v = 38; v ^= 5; assert( v == 35 );
   2057     v = 38; v <<= 1; assert( v == 76 );
   2058     v = 38; v >>= 1; assert( v == 19 );
   2059     v = 38; v += 1;  assert( v < 40 );
   2060 
   2061     v = "abc";
   2062     v ~= "def";
   2063     assert( v == "abcdef", *v.peek!(char[]) );
   2064     assert( Variant(0) < Variant(42) );
   2065     assert( Variant(42) > Variant(0) );
   2066     assert( Variant(42) > Variant(0.1) );
   2067     assert( Variant(42.1) > Variant(1) );
   2068     assert( Variant(21) == Variant(21) );
   2069     assert( Variant(0) != Variant(42) );
   2070     assert( Variant("bar") == Variant("bar") );
   2071     assert( Variant("foo") != Variant("bar") );
   2072 
   2073     {
   2074         auto v1 = Variant(42);
   2075         auto v2 = Variant("foo");
   2076 
   2077         int[Variant] hash;
   2078         hash[v1] = 0;
   2079         hash[v2] = 1;
   2080 
   2081         assert( hash[v1] == 0 );
   2082         assert( hash[v2] == 1 );
   2083     }
   2084 
   2085     {
   2086         int[char[]] hash;
   2087         hash["a"] = 1;
   2088         hash["b"] = 2;
   2089         hash["c"] = 3;
   2090         Variant vhash = hash;
   2091 
   2092         assert( vhash.get!(int[char[]])["a"] == 1 );
   2093         assert( vhash.get!(int[char[]])["b"] == 2 );
   2094         assert( vhash.get!(int[char[]])["c"] == 3 );
   2095     }
   2096 }
   2097 
   2098 @system unittest
   2099 {
   2100     // check comparisons incompatible with AllowedTypes
   2101     Algebraic!int v = 2;
   2102 
   2103     assert(v == 2);
   2104     assert(v < 3);
   2105     static assert(!__traits(compiles, () => v == long.max));
   2106     static assert(!__traits(compiles, () => v == null));
   2107     static assert(!__traits(compiles, () => v < long.max));
   2108     static assert(!__traits(compiles, () => v > null));
   2109 }
   2110 
   2111 // https://issues.dlang.org/show_bug.cgi?id=1558
   2112 @system unittest
   2113 {
   2114     Variant va=1;
   2115     Variant vb=-2;
   2116     assert((va+vb).get!(int) == -1);
   2117     assert((va-vb).get!(int) == 3);
   2118 }
   2119 
   2120 @system unittest
   2121 {
   2122     Variant a;
   2123     a=5;
   2124     Variant b;
   2125     b=a;
   2126     Variant[] c;
   2127     c = variantArray(1, 2, 3.0, "hello", 4);
   2128     assert(c[3] == "hello");
   2129 }
   2130 
   2131 @system unittest
   2132 {
   2133     Variant v = 5;
   2134     assert(!__traits(compiles, v.coerce!(bool delegate())));
   2135 }
   2136 
   2137 
   2138 @system unittest
   2139 {
   2140     struct Huge {
   2141         real a, b, c, d, e, f, g;
   2142     }
   2143 
   2144     Huge huge;
   2145     huge.e = 42;
   2146     Variant v;
   2147     v = huge;  // Compile time error.
   2148     assert(v.get!(Huge).e == 42);
   2149 }
   2150 
   2151 @system unittest
   2152 {
   2153     const x = Variant(42);
   2154     auto y1 = x.get!(const int);
   2155     // @@@BUG@@@
   2156     //auto y2 = x.get!(immutable int)();
   2157 }
   2158 
   2159 // test iteration
   2160 @system unittest
   2161 {
   2162     auto v = Variant([ 1, 2, 3, 4 ][]);
   2163     auto j = 0;
   2164     foreach (int i; v)
   2165     {
   2166         assert(i == ++j);
   2167     }
   2168     assert(j == 4);
   2169 }
   2170 
   2171 // test convertibility
   2172 @system unittest
   2173 {
   2174     auto v = Variant("abc".dup);
   2175     assert(v.convertsTo!(char[]));
   2176 }
   2177 
   2178 // https://issues.dlang.org/show_bug.cgi?id=5424
   2179 @system unittest
   2180 {
   2181     interface A {
   2182         void func1();
   2183     }
   2184     static class AC: A {
   2185         void func1() {
   2186         }
   2187     }
   2188 
   2189     A a = new AC();
   2190     a.func1();
   2191     Variant b = Variant(a);
   2192 }
   2193 
   2194 // https://issues.dlang.org/show_bug.cgi?id=7070
   2195 @system unittest
   2196 {
   2197     Variant v;
   2198     v = null;
   2199 }
   2200 
   2201 // Class and interface opEquals, https://issues.dlang.org/show_bug.cgi?id=12157
   2202 @system unittest
   2203 {
   2204     class Foo { }
   2205 
   2206     class DerivedFoo : Foo { }
   2207 
   2208     Foo f1 = new Foo();
   2209     Foo f2 = new DerivedFoo();
   2210 
   2211     Variant v1 = f1, v2 = f2;
   2212     assert(v1 == f1);
   2213     assert(v1 != new Foo());
   2214     assert(v1 != f2);
   2215     assert(v2 != v1);
   2216     assert(v2 == f2);
   2217 }
   2218 
   2219 // Const parameters with opCall, https://issues.dlang.org/show_bug.cgi?id=11361
   2220 @system unittest
   2221 {
   2222     static string t1(string c) {
   2223         return c ~ "a";
   2224     }
   2225 
   2226     static const(char)[] t2(const(char)[] p) {
   2227         return p ~ "b";
   2228     }
   2229 
   2230     static char[] t3(int p) {
   2231         import std.conv : text;
   2232         return p.text.dup;
   2233     }
   2234 
   2235     Variant v1 = &t1;
   2236     Variant v2 = &t2;
   2237     Variant v3 = &t3;
   2238 
   2239     assert(v1("abc") == "abca");
   2240     assert(v1("abc").type == typeid(string));
   2241     assert(v2("abc") == "abcb");
   2242 
   2243     assert(v2(cast(char[])("abc".dup)) == "abcb");
   2244     assert(v2("abc").type == typeid(const(char)[]));
   2245 
   2246     assert(v3(4) == ['4']);
   2247     assert(v3(4).type == typeid(char[]));
   2248 }
   2249 
   2250 // https://issues.dlang.org/show_bug.cgi?id=12071
   2251 @system unittest
   2252 {
   2253     static struct Structure { int data; }
   2254     alias VariantTest = Algebraic!(Structure delegate() pure nothrow @nogc @safe);
   2255 
   2256     bool called = false;
   2257     Structure example() pure nothrow @nogc @safe
   2258     {
   2259         called = true;
   2260         return Structure.init;
   2261     }
   2262     auto m = VariantTest(&example);
   2263     m();
   2264     assert(called);
   2265 }
   2266 
   2267 // Ordering comparisons of incompatible types
   2268 // e.g. https://issues.dlang.org/show_bug.cgi?id=7990
   2269 @system unittest
   2270 {
   2271     import std.exception : assertThrown;
   2272     assertThrown!VariantException(Variant(3) < "a");
   2273     assertThrown!VariantException("a" < Variant(3));
   2274     assertThrown!VariantException(Variant(3) < Variant("a"));
   2275 
   2276     assertThrown!VariantException(Variant.init < Variant(3));
   2277     assertThrown!VariantException(Variant(3) < Variant.init);
   2278 }
   2279 
   2280 // Handling of unordered types
   2281 // https://issues.dlang.org/show_bug.cgi?id=9043
   2282 @system unittest
   2283 {
   2284     import std.exception : assertThrown;
   2285     static struct A { int a; }
   2286 
   2287     assert(Variant(A(3)) != A(4));
   2288 
   2289     assertThrown!VariantException(Variant(A(3)) < A(4));
   2290     assertThrown!VariantException(A(3) < Variant(A(4)));
   2291     assertThrown!VariantException(Variant(A(3)) < Variant(A(4)));
   2292 }
   2293 
   2294 // Handling of empty types and arrays
   2295 // https://issues.dlang.org/show_bug.cgi?id=10958
   2296 @system unittest
   2297 {
   2298     class EmptyClass { }
   2299     struct EmptyStruct { }
   2300     alias EmptyArray = void[0];
   2301     alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray);
   2302 
   2303     Variant testEmpty(T)()
   2304     {
   2305         T inst;
   2306         Variant v = inst;
   2307         assert(v.get!T == inst);
   2308         assert(v.peek!T !is null);
   2309         assert(*v.peek!T == inst);
   2310         Alg alg = inst;
   2311         assert(alg.get!T == inst);
   2312         return v;
   2313     }
   2314 
   2315     testEmpty!EmptyClass();
   2316     testEmpty!EmptyStruct();
   2317     testEmpty!EmptyArray();
   2318 
   2319     // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0.
   2320     EmptyArray arr = EmptyArray.init;
   2321     Algebraic!(EmptyArray) a = arr;
   2322     assert(a.length == 0);
   2323     assert(a.get!EmptyArray == arr);
   2324 }
   2325 
   2326 // Handling of void function pointers / delegates
   2327 // https://issues.dlang.org/show_bug.cgi?id=11360
   2328 @system unittest
   2329 {
   2330     static void t1() { }
   2331     Variant v = &t1;
   2332     assert(v() == Variant.init);
   2333 
   2334     static int t2() { return 3; }
   2335     Variant v2 = &t2;
   2336     assert(v2() == 3);
   2337 }
   2338 
   2339 // Using peek for large structs
   2340 // https://issues.dlang.org/show_bug.cgi?id=8580
   2341 @system unittest
   2342 {
   2343     struct TestStruct(bool pad)
   2344     {
   2345         int val1;
   2346         static if (pad)
   2347             ubyte[Variant.size] padding;
   2348         int val2;
   2349     }
   2350 
   2351     void testPeekWith(T)()
   2352     {
   2353         T inst;
   2354         inst.val1 = 3;
   2355         inst.val2 = 4;
   2356         Variant v = inst;
   2357         T* original = v.peek!T;
   2358         assert(original.val1 == 3);
   2359         assert(original.val2 == 4);
   2360         original.val1 = 6;
   2361         original.val2 = 8;
   2362         T modified = v.get!T;
   2363         assert(modified.val1 == 6);
   2364         assert(modified.val2 == 8);
   2365     }
   2366 
   2367     testPeekWith!(TestStruct!false)();
   2368     testPeekWith!(TestStruct!true)();
   2369 }
   2370 
   2371 // https://issues.dlang.org/show_bug.cgi?id=18780
   2372 @system unittest
   2373 {
   2374     int x = 7;
   2375     Variant a = x;
   2376     assert(a.convertsTo!ulong);
   2377     assert(a.convertsTo!uint);
   2378 }
   2379 
   2380 /**
   2381  * Applies a delegate or function to the given $(LREF Algebraic) depending on the held type,
   2382  * ensuring that all types are handled by the visiting functions.
   2383  *
   2384  * The delegate or function having the currently held value as parameter is called
   2385  * with `variant`'s current value. Visiting handlers are passed
   2386  * in the template parameter list.
   2387  * It is statically ensured that all held types of
   2388  * `variant` are handled across all handlers.
   2389  * `visit` allows delegates and static functions to be passed
   2390  * as parameters.
   2391  *
   2392  * If a function with an untyped parameter is specified, this function is called
   2393  * when the variant contains a type that does not match any other function.
   2394  * This can be used to apply the same function across multiple possible types.
   2395  * Exactly one generic function is allowed.
   2396  *
   2397  * If a function without parameters is specified, this function is called
   2398  * when `variant` doesn't hold a value. Exactly one parameter-less function
   2399  * is allowed.
   2400  *
   2401  * Duplicate overloads matching the same type in one of the visitors are disallowed.
   2402  *
   2403  * Returns: The return type of visit is deduced from the visiting functions and must be
   2404  * the same across all overloads.
   2405  * Throws: $(LREF VariantException) if `variant` doesn't hold a value and no
   2406  * parameter-less fallback function is specified.
   2407  */
   2408 template visit(Handlers...)
   2409 if (Handlers.length > 0)
   2410 {
   2411     ///
   2412     auto visit(VariantType)(VariantType variant)
   2413         if (isAlgebraic!VariantType)
   2414     {
   2415         return visitImpl!(true, VariantType, Handlers)(variant);
   2416     }
   2417 }
   2418 
   2419 ///
   2420 @system unittest
   2421 {
   2422     Algebraic!(int, string) variant;
   2423 
   2424     variant = 10;
   2425     assert(variant.visit!((string s) => cast(int) s.length,
   2426                           (int i)    => i)()
   2427                           == 10);
   2428     variant = "string";
   2429     assert(variant.visit!((int i) => i,
   2430                           (string s) => cast(int) s.length)()
   2431                           == 6);
   2432 
   2433     // Error function usage
   2434     Algebraic!(int, string) emptyVar;
   2435     auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
   2436                           (int i)    => i,
   2437                           () => -1)();
   2438     assert(rslt == -1);
   2439 
   2440     // Generic function usage
   2441     Algebraic!(int, float, real) number = 2;
   2442     assert(number.visit!(x => x += 1) == 3);
   2443 
   2444     // Generic function for int/float with separate behavior for string
   2445     Algebraic!(int, float, string) something = 2;
   2446     assert(something.visit!((string s) => s.length, x => x) == 2); // generic
   2447     something = "asdf";
   2448     assert(something.visit!((string s) => s.length, x => x) == 4); // string
   2449 
   2450     // Generic handler and empty handler
   2451     Algebraic!(int, float, real) empty2;
   2452     assert(empty2.visit!(x => x + 1, () => -1) == -1);
   2453 }
   2454 
   2455 @system unittest
   2456 {
   2457     Algebraic!(size_t, string) variant;
   2458 
   2459     // not all handled check
   2460     static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
   2461 
   2462     variant = cast(size_t) 10;
   2463     auto which = 0;
   2464     variant.visit!( (string s) => which = 1,
   2465                     (size_t i) => which = 0
   2466                     )();
   2467 
   2468     // integer overload was called
   2469     assert(which == 0);
   2470 
   2471     // mustn't compile as generic Variant not supported
   2472     Variant v;
   2473     static assert(!__traits(compiles, v.visit!((string s) => which = 1,
   2474                                                (size_t i) => which = 0
   2475                                                 )()
   2476                                                 ));
   2477 
   2478     static size_t func(string s) {
   2479         return s.length;
   2480     }
   2481 
   2482     variant = "test";
   2483     assert( 4 == variant.visit!(func,
   2484                                 (size_t i) => i
   2485                                 )());
   2486 
   2487     Algebraic!(int, float, string) variant2 = 5.0f;
   2488     // Shouldn' t compile as float not handled by visitor.
   2489     static assert(!__traits(compiles, variant2.visit!(
   2490                         (int _) {},
   2491                         (string _) {})()));
   2492 
   2493     Algebraic!(size_t, string, float) variant3;
   2494     variant3 = 10.0f;
   2495     auto floatVisited = false;
   2496 
   2497     assert(variant3.visit!(
   2498                  (float f) { floatVisited = true; return cast(size_t) f; },
   2499                  func,
   2500                  (size_t i) { return i; }
   2501                  )() == 10);
   2502     assert(floatVisited == true);
   2503 
   2504     Algebraic!(float, string) variant4;
   2505 
   2506     assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
   2507 
   2508     // double error func check
   2509     static assert(!__traits(compiles,
   2510                             visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
   2511                  );
   2512 }
   2513 
   2514 // disallow providing multiple generic handlers to visit
   2515 // disallow a generic handler that does not apply to all types
   2516 @system unittest
   2517 {
   2518     Algebraic!(int, float) number = 2;
   2519     // ok, x + 1 valid for int and float
   2520     static assert( __traits(compiles, number.visit!(x => x + 1)));
   2521     // bad, two generic handlers
   2522     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
   2523     // bad, x ~ "a" does not apply to int or float
   2524     static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
   2525     // bad, x ~ "a" does not apply to int or float
   2526     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
   2527 
   2528     Algebraic!(int, string) maybenumber = 2;
   2529     // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
   2530     static assert( __traits(compiles, maybenumber.visit!((string x) => x ~ "a", x => "foobar"[0 .. x + 1])));
   2531     // bad, x ~ "a" valid for string but not int
   2532     static assert(!__traits(compiles, maybenumber.visit!(x => x ~ "a")));
   2533     // bad, two generics, each only applies in one case
   2534     static assert(!__traits(compiles, maybenumber.visit!(x => x + 1, x => x ~ "a")));
   2535 }
   2536 
   2537 /**
   2538  * Behaves as $(LREF visit) but doesn't enforce that all types are handled
   2539  * by the visiting functions.
   2540  *
   2541  * If a parameter-less function is specified it is called when
   2542  * either `variant` doesn't hold a value or holds a type
   2543  * which isn't handled by the visiting functions.
   2544  *
   2545  * Returns: The return type of tryVisit is deduced from the visiting functions and must be
   2546  * the same across all overloads.
   2547  * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
   2548  * `variant` holds a value which isn't handled by the visiting functions,
   2549  * when no parameter-less fallback function is specified.
   2550  */
   2551 template tryVisit(Handlers...)
   2552 if (Handlers.length > 0)
   2553 {
   2554     ///
   2555     auto tryVisit(VariantType)(VariantType variant)
   2556         if (isAlgebraic!VariantType)
   2557     {
   2558         return visitImpl!(false, VariantType, Handlers)(variant);
   2559     }
   2560 }
   2561 
   2562 ///
   2563 @system unittest
   2564 {
   2565     Algebraic!(int, string) variant;
   2566 
   2567     variant = 10;
   2568     auto which = -1;
   2569     variant.tryVisit!((int i) { which = 0; })();
   2570     assert(which == 0);
   2571 
   2572     // Error function usage
   2573     variant = "test";
   2574     variant.tryVisit!((int i) { which = 0; },
   2575                       ()      { which = -100; })();
   2576     assert(which == -100);
   2577 }
   2578 
   2579 @system unittest
   2580 {
   2581     import std.exception : assertThrown;
   2582     Algebraic!(int, string) variant;
   2583 
   2584     variant = 10;
   2585     auto which = -1;
   2586     variant.tryVisit!((int i){ which = 0; })();
   2587 
   2588     assert(which == 0);
   2589 
   2590     variant = "test";
   2591 
   2592     assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
   2593 
   2594     void errorfunc()
   2595     {
   2596         which = -1;
   2597     }
   2598 
   2599     variant.tryVisit!((int i) { which = 0; }, errorfunc)();
   2600 
   2601     assert(which == -1);
   2602 }
   2603 
   2604 private template isAlgebraic(Type)
   2605 {
   2606     static if (is(Type _ == VariantN!T, T...))
   2607         enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
   2608     else
   2609         enum isAlgebraic = false;
   2610 }
   2611 
   2612 @system unittest
   2613 {
   2614     static assert(!isAlgebraic!(Variant));
   2615     static assert( isAlgebraic!(Algebraic!(string)));
   2616     static assert( isAlgebraic!(Algebraic!(int, int[])));
   2617 }
   2618 
   2619 private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
   2620 if (isAlgebraic!VariantType && Handler.length > 0)
   2621 {
   2622     alias AllowedTypes = VariantType.AllowedTypes;
   2623 
   2624 
   2625     /**
   2626      * Returns: Struct where `indices`  is an array which
   2627      * contains at the n-th position the index in Handler which takes the
   2628      * n-th type of AllowedTypes. If an Handler doesn't match an
   2629      * AllowedType, -1 is set. If a function in the delegates doesn't
   2630      * have parameters, the field `exceptionFuncIdx` is set;
   2631      * otherwise it's -1.
   2632      */
   2633     auto visitGetOverloadMap()
   2634     {
   2635         struct Result {
   2636             int[AllowedTypes.length] indices;
   2637             int exceptionFuncIdx = -1;
   2638             int generalFuncIdx = -1;
   2639         }
   2640 
   2641         Result result;
   2642 
   2643         enum int nonmatch = ()
   2644         {
   2645             foreach (int dgidx, dg; Handler)
   2646             {
   2647                 bool found = false;
   2648                 foreach (T; AllowedTypes)
   2649                 {
   2650                     found |= __traits(compiles, { static assert(isSomeFunction!(dg!T)); });
   2651                     found |= __traits(compiles, (T t) { dg(t); });
   2652                     found |= __traits(compiles, dg());
   2653                 }
   2654                 if (!found) return dgidx;
   2655             }
   2656             return -1;
   2657         }();
   2658         static assert(nonmatch == -1, "No match for visit handler #"~
   2659             nonmatch.stringof~" ("~Handler[nonmatch].stringof~")");
   2660 
   2661         foreach (tidx, T; AllowedTypes)
   2662         {
   2663             bool added = false;
   2664             foreach (dgidx, dg; Handler)
   2665             {
   2666                 // Handle normal function objects
   2667                 static if (isSomeFunction!dg)
   2668                 {
   2669                     alias Params = Parameters!dg;
   2670                     static if (Params.length == 0)
   2671                     {
   2672                         // Just check exception functions in the first
   2673                         // inner iteration (over delegates)
   2674                         if (tidx > 0)
   2675                             continue;
   2676                         else
   2677                         {
   2678                             if (result.exceptionFuncIdx != -1)
   2679                                 assert(false, "duplicate parameter-less (error-)function specified");
   2680                             result.exceptionFuncIdx = dgidx;
   2681                         }
   2682                     }
   2683                     else static if (is(Params[0] == T) || is(Unqual!(Params[0]) == T))
   2684                     {
   2685                         if (added)
   2686                             assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'");
   2687 
   2688                         added = true;
   2689                         result.indices[tidx] = dgidx;
   2690                     }
   2691                 }
   2692                 else static if (__traits(compiles, { static assert(isSomeFunction!(dg!T)); }))
   2693                 {
   2694                     assert(result.generalFuncIdx == -1 ||
   2695                            result.generalFuncIdx == dgidx,
   2696                            "Only one generic visitor function is allowed");
   2697                     result.generalFuncIdx = dgidx;
   2698                 }
   2699                 // Handle composite visitors with opCall overloads
   2700             }
   2701 
   2702             if (!added)
   2703                 result.indices[tidx] = -1;
   2704         }
   2705 
   2706         return result;
   2707     }
   2708 
   2709     enum HandlerOverloadMap = visitGetOverloadMap();
   2710 
   2711     if (!variant.hasValue)
   2712     {
   2713         // Call the exception function. The HandlerOverloadMap
   2714         // will have its exceptionFuncIdx field set to value != -1 if an
   2715         // exception function has been specified; otherwise we just through an exception.
   2716         static if (HandlerOverloadMap.exceptionFuncIdx != -1)
   2717             return Handler[ HandlerOverloadMap.exceptionFuncIdx ]();
   2718         else
   2719             throw new VariantException("variant must hold a value before being visited.");
   2720     }
   2721 
   2722     foreach (idx, T; AllowedTypes)
   2723     {
   2724         if (auto ptr = variant.peek!T)
   2725         {
   2726             enum dgIdx = HandlerOverloadMap.indices[idx];
   2727 
   2728             static if (dgIdx == -1)
   2729             {
   2730                 static if (HandlerOverloadMap.generalFuncIdx >= 0)
   2731                     return Handler[HandlerOverloadMap.generalFuncIdx](*ptr);
   2732                 else static if (Strict)
   2733                     static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified");
   2734                 else static if (HandlerOverloadMap.exceptionFuncIdx != -1)
   2735                     return Handler[HandlerOverloadMap.exceptionFuncIdx]();
   2736                 else
   2737                     throw new VariantException(
   2738                         "variant holds value of type '"
   2739                         ~ T.stringof ~
   2740                         "' but no visitor has been provided"
   2741                     );
   2742             }
   2743             else
   2744             {
   2745                 return Handler[ dgIdx ](*ptr);
   2746             }
   2747         }
   2748     }
   2749 
   2750     assert(false);
   2751 }
   2752 
   2753 // https://issues.dlang.org/show_bug.cgi?id=21253
   2754 @system unittest
   2755 {
   2756     static struct A { int n; }
   2757     static struct B {        }
   2758 
   2759     auto a = Algebraic!(A, B)(B());
   2760     assert(a.visit!(
   2761         (B _) => 42,
   2762         (a  ) => a.n
   2763     ) == 42);
   2764 }
   2765 
   2766 @system unittest
   2767 {
   2768     // validate that visit can be called with a const type
   2769     struct Foo { int depth; }
   2770     struct Bar { int depth; }
   2771     alias FooBar = Algebraic!(Foo, Bar);
   2772 
   2773     int depth(in FooBar fb) {
   2774         return fb.visit!((Foo foo) => foo.depth,
   2775                          (Bar bar) => bar.depth);
   2776     }
   2777 
   2778     FooBar fb = Foo(3);
   2779     assert(depth(fb) == 3);
   2780 }
   2781 
   2782 // https://issues.dlang.org/show_bug.cgi?id=16383
   2783 @system unittest
   2784 {
   2785     class Foo {this() immutable {}}
   2786     alias V = Algebraic!(immutable Foo);
   2787 
   2788     auto x = V(new immutable Foo).visit!(
   2789         (immutable(Foo) _) => 3
   2790     );
   2791     assert(x == 3);
   2792 }
   2793 
   2794 // https://issues.dlang.org/show_bug.cgi?id=5310
   2795 @system unittest
   2796 {
   2797     const Variant a;
   2798     assert(a == a);
   2799     Variant b;
   2800     assert(a == b);
   2801     assert(b == a);
   2802 }
   2803 
   2804 @system unittest
   2805 {
   2806     const Variant a = [2];
   2807     assert(a[0] == 2);
   2808 }
   2809 
   2810 // https://issues.dlang.org/show_bug.cgi?id=10017
   2811 @system unittest
   2812 {
   2813     static struct S
   2814     {
   2815         ubyte[Variant.size + 1] s;
   2816     }
   2817 
   2818     Variant v1, v2;
   2819     v1 = S(); // the payload is allocated on the heap
   2820     v2 = v1;  // AssertError: target must be non-null
   2821     assert(v1 == v2);
   2822 }
   2823 
   2824 // https://issues.dlang.org/show_bug.cgi?id=7069
   2825 @system unittest
   2826 {
   2827     import std.exception : assertThrown;
   2828     Variant v;
   2829 
   2830     int i = 10;
   2831     v = i;
   2832     static foreach (qual; AliasSeq!(Alias, ConstOf))
   2833     {
   2834         assert(v.get!(qual!int) == 10);
   2835         assert(v.get!(qual!float) == 10.0f);
   2836     }
   2837     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
   2838     {
   2839         assertThrown!VariantException(v.get!(qual!int));
   2840     }
   2841 
   2842     const(int) ci = 20;
   2843     v = ci;
   2844     static foreach (qual; AliasSeq!(ConstOf))
   2845     {
   2846         assert(v.get!(qual!int) == 20);
   2847         assert(v.get!(qual!float) == 20.0f);
   2848     }
   2849     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
   2850     {
   2851         assertThrown!VariantException(v.get!(qual!int));
   2852         assertThrown!VariantException(v.get!(qual!float));
   2853     }
   2854 
   2855     immutable(int) ii = ci;
   2856     v = ii;
   2857     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
   2858     {
   2859         assert(v.get!(qual!int) == 20);
   2860         assert(v.get!(qual!float) == 20.0f);
   2861     }
   2862     static foreach (qual; AliasSeq!(Alias, SharedOf))
   2863     {
   2864         assertThrown!VariantException(v.get!(qual!int));
   2865         assertThrown!VariantException(v.get!(qual!float));
   2866     }
   2867 
   2868     int[] ai = [1,2,3];
   2869     v = ai;
   2870     static foreach (qual; AliasSeq!(Alias, ConstOf))
   2871     {
   2872         assert(v.get!(qual!(int[])) == [1,2,3]);
   2873         assert(v.get!(qual!(int)[]) == [1,2,3]);
   2874     }
   2875     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
   2876     {
   2877         assertThrown!VariantException(v.get!(qual!(int[])));
   2878         assertThrown!VariantException(v.get!(qual!(int)[]));
   2879     }
   2880 
   2881     const(int[]) cai = [4,5,6];
   2882     v = cai;
   2883     static foreach (qual; AliasSeq!(ConstOf))
   2884     {
   2885         assert(v.get!(qual!(int[])) == [4,5,6]);
   2886         assert(v.get!(qual!(int)[]) == [4,5,6]);
   2887     }
   2888     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
   2889     {
   2890         assertThrown!VariantException(v.get!(qual!(int[])));
   2891         assertThrown!VariantException(v.get!(qual!(int)[]));
   2892     }
   2893 
   2894     immutable(int[]) iai = [7,8,9];
   2895     v = iai;
   2896     //assert(v.get!(immutable(int[])) == [7,8,9]);   // Bug ??? runtime error
   2897     assert(v.get!(immutable(int)[]) == [7,8,9]);
   2898     assert(v.get!(const(int[])) == [7,8,9]);
   2899     assert(v.get!(const(int)[]) == [7,8,9]);
   2900     //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
   2901     //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
   2902     static foreach (qual; AliasSeq!(Alias))
   2903     {
   2904         assertThrown!VariantException(v.get!(qual!(int[])));
   2905         assertThrown!VariantException(v.get!(qual!(int)[]));
   2906     }
   2907 
   2908     class A {}
   2909     class B : A {}
   2910     B b = new B();
   2911     v = b;
   2912     static foreach (qual; AliasSeq!(Alias, ConstOf))
   2913     {
   2914         assert(v.get!(qual!B) is b);
   2915         assert(v.get!(qual!A) is b);
   2916         assert(v.get!(qual!Object) is b);
   2917     }
   2918     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
   2919     {
   2920         assertThrown!VariantException(v.get!(qual!B));
   2921         assertThrown!VariantException(v.get!(qual!A));
   2922         assertThrown!VariantException(v.get!(qual!Object));
   2923     }
   2924 
   2925     const(B) cb = new B();
   2926     v = cb;
   2927     static foreach (qual; AliasSeq!(ConstOf))
   2928     {
   2929         assert(v.get!(qual!B) is cb);
   2930         assert(v.get!(qual!A) is cb);
   2931         assert(v.get!(qual!Object) is cb);
   2932     }
   2933     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
   2934     {
   2935         assertThrown!VariantException(v.get!(qual!B));
   2936         assertThrown!VariantException(v.get!(qual!A));
   2937         assertThrown!VariantException(v.get!(qual!Object));
   2938     }
   2939 
   2940     immutable(B) ib = new immutable(B)();
   2941     v = ib;
   2942     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
   2943     {
   2944         assert(v.get!(qual!B) is ib);
   2945         assert(v.get!(qual!A) is ib);
   2946         assert(v.get!(qual!Object) is ib);
   2947     }
   2948     static foreach (qual; AliasSeq!(Alias, SharedOf))
   2949     {
   2950         assertThrown!VariantException(v.get!(qual!B));
   2951         assertThrown!VariantException(v.get!(qual!A));
   2952         assertThrown!VariantException(v.get!(qual!Object));
   2953     }
   2954 
   2955     shared(B) sb = new shared B();
   2956     v = sb;
   2957     static foreach (qual; AliasSeq!(SharedOf, SharedConstOf))
   2958     {
   2959         assert(v.get!(qual!B) is sb);
   2960         assert(v.get!(qual!A) is sb);
   2961         assert(v.get!(qual!Object) is sb);
   2962     }
   2963     static foreach (qual; AliasSeq!(Alias, ImmutableOf, ConstOf))
   2964     {
   2965         assertThrown!VariantException(v.get!(qual!B));
   2966         assertThrown!VariantException(v.get!(qual!A));
   2967         assertThrown!VariantException(v.get!(qual!Object));
   2968     }
   2969 
   2970     shared(const(B)) scb = new shared const B();
   2971     v = scb;
   2972     static foreach (qual; AliasSeq!(SharedConstOf))
   2973     {
   2974         assert(v.get!(qual!B) is scb);
   2975         assert(v.get!(qual!A) is scb);
   2976         assert(v.get!(qual!Object) is scb);
   2977     }
   2978     static foreach (qual; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf))
   2979     {
   2980         assertThrown!VariantException(v.get!(qual!B));
   2981         assertThrown!VariantException(v.get!(qual!A));
   2982         assertThrown!VariantException(v.get!(qual!Object));
   2983     }
   2984 }
   2985 
   2986 // https://issues.dlang.org/show_bug.cgi?id=12540
   2987 @system unittest
   2988 {
   2989     static struct DummyScope
   2990     {
   2991         alias Alias12540 = Algebraic!Class12540;
   2992 
   2993         static class Class12540
   2994         {
   2995             Alias12540 entity;
   2996         }
   2997     }
   2998 }
   2999 
   3000 @system unittest
   3001 {
   3002     // https://issues.dlang.org/show_bug.cgi?id=10194
   3003     // Also test for elaborate copying
   3004     static struct S
   3005     {
   3006         @disable this();
   3007         this(int dummy)
   3008         {
   3009             ++cnt;
   3010         }
   3011 
   3012         this(this)
   3013         {
   3014             ++cnt;
   3015         }
   3016 
   3017         @disable S opAssign();
   3018 
   3019         ~this()
   3020         {
   3021             --cnt;
   3022             assert(cnt >= 0);
   3023         }
   3024         static int cnt = 0;
   3025     }
   3026 
   3027     {
   3028         Variant v;
   3029         {
   3030             v = S(0);
   3031             assert(S.cnt == 1);
   3032         }
   3033         assert(S.cnt == 1);
   3034 
   3035         // assigning a new value should destroy the existing one
   3036         v = 0;
   3037         assert(S.cnt == 0);
   3038 
   3039         // destroying the variant should destroy it's current value
   3040         v = S(0);
   3041         assert(S.cnt == 1);
   3042     }
   3043     assert(S.cnt == 0);
   3044 }
   3045 
   3046 @system unittest
   3047 {
   3048     // https://issues.dlang.org/show_bug.cgi?id=13300
   3049     static struct S
   3050     {
   3051         this(this) {}
   3052         ~this() {}
   3053     }
   3054 
   3055     static assert( hasElaborateCopyConstructor!(Variant));
   3056     static assert(!hasElaborateCopyConstructor!(Algebraic!bool));
   3057     static assert( hasElaborateCopyConstructor!(Algebraic!S));
   3058     static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S)));
   3059 
   3060     static assert( hasElaborateDestructor!(Variant));
   3061     static assert(!hasElaborateDestructor!(Algebraic!bool));
   3062     static assert( hasElaborateDestructor!(Algebraic!S));
   3063     static assert( hasElaborateDestructor!(Algebraic!(bool, S)));
   3064 
   3065     import std.array;
   3066     alias Value = Algebraic!bool;
   3067 
   3068     static struct T
   3069     {
   3070         Value value;
   3071         @disable this();
   3072     }
   3073     auto a = appender!(T[]);
   3074 }
   3075 
   3076 // https://issues.dlang.org/show_bug.cgi?id=13871
   3077 @system unittest
   3078 {
   3079     alias A = Algebraic!(int, typeof(null));
   3080     static struct B { A value; }
   3081     alias C = std.variant.Algebraic!B;
   3082 
   3083     C var;
   3084     var = C(B());
   3085 }
   3086 
   3087 @system unittest
   3088 {
   3089     import std.exception : assertThrown, assertNotThrown;
   3090     // Make sure Variant can handle types with opDispatch but no length field.
   3091     struct SWithNoLength
   3092     {
   3093         void opDispatch(string s)() { }
   3094     }
   3095 
   3096     struct SWithLength
   3097     {
   3098         @property int opDispatch(string s)()
   3099         {
   3100             // Assume that s == "length"
   3101             return 5; // Any value is OK for test.
   3102         }
   3103     }
   3104 
   3105     SWithNoLength sWithNoLength;
   3106     Variant v = sWithNoLength;
   3107     assertThrown!VariantException(v.length);
   3108 
   3109     SWithLength sWithLength;
   3110     v = sWithLength;
   3111     assertNotThrown!VariantException(v.get!SWithLength.length);
   3112     assertThrown!VariantException(v.length);
   3113 }
   3114 
   3115 // https://issues.dlang.org/show_bug.cgi?id=13534
   3116 @system unittest
   3117 {
   3118     static assert(!__traits(compiles, () @safe {
   3119         auto foo() @system { return 3; }
   3120         auto v = Variant(&foo);
   3121         v(); // foo is called in safe code!?
   3122     }));
   3123 }
   3124 
   3125 // https://issues.dlang.org/show_bug.cgi?id=15039
   3126 @system unittest
   3127 {
   3128     import std.typecons;
   3129     import std.variant;
   3130 
   3131     alias IntTypedef = Typedef!int;
   3132     alias Obj = Algebraic!(int, IntTypedef, This[]);
   3133 
   3134     Obj obj = 1;
   3135 
   3136     obj.visit!(
   3137         (int x) {},
   3138         (IntTypedef x) {},
   3139         (Obj[] x) {},
   3140     );
   3141 }
   3142 
   3143 // https://issues.dlang.org/show_bug.cgi?id=15791
   3144 @system unittest
   3145 {
   3146     int n = 3;
   3147     struct NS1 { int foo() { return n + 10; } }
   3148     struct NS2 { int foo() { return n * 10; } }
   3149 
   3150     Variant v;
   3151     v = NS1();
   3152     assert(v.get!NS1.foo() == 13);
   3153     v = NS2();
   3154     assert(v.get!NS2.foo() == 30);
   3155 }
   3156 
   3157 // https://issues.dlang.org/show_bug.cgi?id=15827
   3158 @system unittest
   3159 {
   3160     static struct Foo15827 { Variant v; this(Foo15827 v) {} }
   3161     Variant v = Foo15827.init;
   3162 }
   3163 
   3164 // https://issues.dlang.org/show_bug.cgi?id=18934
   3165 @system unittest
   3166 {
   3167     static struct S
   3168     {
   3169         const int x;
   3170     }
   3171 
   3172     auto s = S(42);
   3173     Variant v = s;
   3174     auto s2 = v.get!S;
   3175     assert(s2.x == 42);
   3176     Variant v2 = v; // support copying from one variant to the other
   3177     v2 = S(2);
   3178     v = v2;
   3179     assert(v.get!S.x == 2);
   3180 }
   3181 
   3182 // https://issues.dlang.org/show_bug.cgi?id=19200
   3183 @system unittest
   3184 {
   3185     static struct S
   3186     {
   3187         static int opBinaryRight(string op : "|", T)(T rhs)
   3188         {
   3189             return 3;
   3190         }
   3191     }
   3192 
   3193     S s;
   3194     Variant v;
   3195     auto b = v | s;
   3196     assert(b == 3);
   3197 }
   3198 
   3199 // https://issues.dlang.org/show_bug.cgi?id=11061
   3200 @system unittest
   3201 {
   3202     int[4] el = [0, 1, 2, 3];
   3203     int[3] nl = [0, 1, 2];
   3204     Variant v1 = el;
   3205     assert(v1 == el); // Compare Var(static) to static
   3206     assert(v1 != nl); // Compare static arrays of different length
   3207     assert(v1 == [0, 1, 2, 3]); // Compare Var(static) to dynamic.
   3208     assert(v1 != [0, 1, 2]);
   3209     int[] dyn = [0, 1, 2, 3];
   3210     v1 = dyn;
   3211     assert(v1 == el); // Compare Var(dynamic) to static.
   3212     assert(v1 == [0, 1] ~ [2, 3]); // Compare Var(dynamic) to dynamic
   3213 }
   3214 
   3215 // https://issues.dlang.org/show_bug.cgi?id=15940
   3216 @system unittest
   3217 {
   3218     class C { }
   3219     struct S
   3220     {
   3221         C a;
   3222         alias a this;
   3223     }
   3224     S s = S(new C());
   3225     auto v = Variant(s); // compile error
   3226 }
   3227 
   3228 @system unittest
   3229 {
   3230     // Test if we don't have scoping issues.
   3231     Variant createVariant(int[] input)
   3232     {
   3233         int[2] el = [input[0], input[1]];
   3234         Variant v = el;
   3235         return v;
   3236     }
   3237     Variant v = createVariant([0, 1]);
   3238     createVariant([2, 3]);
   3239     assert(v == [0,1]);
   3240 }
   3241 
   3242 // https://issues.dlang.org/show_bug.cgi?id=19994
   3243 @safe unittest
   3244 {
   3245     alias Inner = Algebraic!(This*);
   3246     alias Outer = Algebraic!(Inner, This*);
   3247 
   3248     static assert(is(Outer.AllowedTypes == AliasSeq!(Inner, Outer*)));
   3249 }
   3250 
   3251 // https://issues.dlang.org/show_bug.cgi?id=21296
   3252 @system unittest
   3253 {
   3254     immutable aa = ["0": 0];
   3255     auto v = Variant(aa); // compile error
   3256 }
   3257