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