1// Written in the D programming language.
2
3/**
4This module implements a
5$(HTTP erdani.org/publications/cuj-04-2002.php.html,discriminated union)
6type (a.k.a.
7$(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
8$(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
9Such types are useful
10for type-uniform binary interfaces, interfacing with scripting
11languages, and comfortable exploratory programming.
12
13A $(LREF Variant) object can hold a value of any type, with very few
14restrictions (such as `shared` types and noncopyable types). Setting the value
15is as immediate as assigning to the `Variant` object. To read back the value of
16the 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
18exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19the current value.
20
21In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
22type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
23types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
24string)) may only hold an `int` or a `string`).
25
26$(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
27code. Instead, use $(REF SumType, std,sumtype).)
28
29Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
30prompting the following improvements: (1) better support for arrays; (2) support
31for associative arrays; (3) friendlier behavior towards the garbage collector.
32Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
33License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
34Authors:   $(HTTP erdani.org, Andrei Alexandrescu)
35Source:    $(PHOBOSSRC std/variant.d)
36*/
37module std.variant;
38
39import 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  +/
83template 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
129struct This;
130
131private 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.
135private template maxVariantAlignment(U...)
136if (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 */
174struct 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
181private:
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
647public:
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
1445pure 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
1663types. It's an alias for $(LREF VariantN) with an
1664appropriately-constructed maximum size. `Algebraic` is
1665useful when it is desirable to restrict what a discriminated type
1666could hold to the end of defining simpler and more efficient
1667manipulation.
1668
1669$(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
1670code. Instead, use $(REF SumType, std,sumtype).)
1671*/
1672template 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
1691A useful and popular use of algebraic data structures is for defining $(LUCKY
1692self-referential data structures), i.e. structures that embed references to
1693values of their own type within.
1694
1695This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1696reference to the type being defined is needed. The `Algebraic` instantiation
1697will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1698alpha renaming) on its constituent types, replacing `This`
1699with the self-referenced type. The structure of the type involving `This` may
1700be 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
1722private struct FakeComplexReal
1723{
1724    real re, im;
1725}
1726
1727/**
1728Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1729`char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1730to hold all of D's predefined types unboxed, including all numeric types,
1731pointers, delegates, and class references.  You may want to use
1732`VariantN` directly with a different maximum size either for
1733storing larger types unboxed, or for saving memory.
1734 */
1735alias 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 */
1789Variant[] 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
1820static 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 */
2408template visit(Handlers...)
2409if (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 */
2551template tryVisit(Handlers...)
2552if (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
2604private 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
2619private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2620if (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