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() cast(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)
1195     if (is(Delegate == delegate))
1196     {
1197         alias A = Parameters!(Delegate)[0];
1198         if (type == typeid(A[]))
1199         {
1200             auto arr = get!(A[]);
1201             foreach (ref e; arr)
1202             {
1203                 if (dg(e)) return 1;
1204             }
1205         }
1206         else static if (is(A == VariantN))
1207         {
1208             foreach (i; 0 .. length)
1209             {
1210                 // @@@TODO@@@: find a better way to not confuse
1211                 // clients who think they change values stored in the
1212                 // Variant when in fact they are only changing tmp.
1213                 auto tmp = this[i];
1214                 debug scope(exit) assert(tmp == this[i]);
1215                 if (dg(tmp)) return 1;
1216             }
1217         }
1218         else
1219         {
1220             import std.conv : text;
1221             import std.exception : enforce;
1222             enforce(false, text("Variant type ", type,
1223                             " not iterable with values of type ",
1224                             A.stringof));
1225         }
1226         return 0;
1227     }
1228 }
1229 
1230 ///
1231 @system unittest
1232 {
1233     alias Var = VariantN!(maxSize!(int, double, string));
1234 
1235     Var a; // Must assign before use, otherwise exception ensues
1236     // Initialize with an integer; make the type int
1237     Var b = 42;
1238     assert(b.type == typeid(int));
1239     // Peek at the value
1240     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1241     // Automatically convert per language rules
1242     auto x = b.get!(real);
1243 
1244     // Assign any other type, including other variants
1245     a = b;
1246     a = 3.14;
1247     assert(a.type == typeid(double));
1248     // Implicit conversions work just as with built-in types
1249     assert(a < b);
1250     // Check for convertibility
1251     assert(!a.convertsTo!(int)); // double not convertible to int
1252     // Strings and all other arrays are supported
1253     a = "now I'm a string";
1254     assert(a == "now I'm a string");
1255 }
1256 
1257 /// can also assign arrays
1258 @system unittest
1259 {
1260     alias Var = VariantN!(maxSize!(int[]));
1261 
1262     Var a = new int[42];
1263     assert(a.length == 42);
1264     a[5] = 7;
1265     assert(a[5] == 7);
1266 }
1267 
1268 @safe unittest
1269 {
1270     alias V = VariantN!24;
1271     const alignMask = V.alignof - 1;
1272     assert(V.sizeof == ((24 + (void*).sizeof + alignMask) & ~alignMask));
1273 }
1274 
1275 /// Can also assign class values
1276 @system unittest
1277 {
1278     alias Var = VariantN!(maxSize!(int*)); // classes are pointers
1279     Var a;
1280 
1281     class Foo {}
1282     auto foo = new Foo;
1283     a = foo;
1284     assert(*a.peek!(Foo) == foo); // and full type information is preserved
1285 }
1286 
1287 @system unittest
1288 {
1289     import std.conv : to;
1290     Variant v;
1291     int foo() { return 42; }
1292     v = &foo;
1293     assert(v() == 42);
1294 
1295     static int bar(string s) { return to!int(s); }
1296     v = &bar;
1297     assert(v("43") == 43);
1298 }
1299 
1300 @system unittest
1301 {
1302     int[int] hash = [ 42:24 ];
1303     Variant v = hash;
1304     assert(v[42] == 24);
1305     v[42] = 5;
1306     assert(v[42] == 5);
1307 }
1308 
1309 // opIndex with static arrays, https://issues.dlang.org/show_bug.cgi?id=12771
1310 @system unittest
1311 {
1312     int[4] elements = [0, 1, 2, 3];
1313     Variant v = elements;
1314     assert(v == elements);
1315     assert(v[2] == 2);
1316     assert(v[3] == 3);
1317     v[2] = 6;
1318     assert(v[2] == 6);
1319     assert(v != elements);
1320 }
1321 
1322 @system unittest
1323 {
1324     import std.exception : assertThrown;
1325     Algebraic!(int[]) v = [2, 2];
1326 
1327     assert(v == [2, 2]);
1328     v[0] = 1;
1329     assert(v[0] == 1);
1330     assert(v != [2, 2]);
1331 
1332     // opIndexAssign from Variant
1333     v[1] = v[0];
1334     assert(v[1] == 1);
1335 
1336     static assert(!__traits(compiles, (v[1] = null)));
1337     assertThrown!VariantException(v[1] = Variant(null));
1338 }
1339 
1340 // https://issues.dlang.org/show_bug.cgi?id=10879
1341 @system unittest
1342 {
1343     int[10] arr = [1,2,3,4,5,6,7,8,9,10];
1344     Variant v1 = arr;
1345     Variant v2;
1346     v2 = arr;
1347     assert(v1 == arr);
1348     assert(v2 == arr);
1349     foreach (i, e; arr)
1350     {
1351         assert(v1[i] == e);
1352         assert(v2[i] == e);
1353     }
1354     static struct LargeStruct
1355     {
1356         int[100] data;
1357     }
1358     LargeStruct ls;
1359     ls.data[] = 4;
1360     v1 = ls;
1361     Variant v3 = ls;
1362     assert(v1 == ls);
1363     assert(v3 == ls);
1364 }
1365 
1366 // https://issues.dlang.org/show_bug.cgi?id=8195
1367 @system unittest
1368 {
1369     struct S
1370     {
1371         int a;
1372         long b;
1373         string c;
1374         real d = 0.0;
1375         bool e;
1376     }
1377 
1378     static assert(S.sizeof >= Variant.sizeof);
1379     alias Types = AliasSeq!(string, int, S);
1380     alias MyVariant = VariantN!(maxSize!Types, Types);
1381 
1382     auto v = MyVariant(S.init);
1383     assert(v == S.init);
1384 }
1385 
1386 // https://issues.dlang.org/show_bug.cgi?id=10961
1387 @system unittest
1388 {
1389     // Primarily test that we can assign a void[] to a Variant.
1390     void[] elements = cast(void[])[1, 2, 3];
1391     Variant v = elements;
1392     void[] returned = v.get!(void[]);
1393     assert(returned == elements);
1394 }
1395 
1396 // https://issues.dlang.org/show_bug.cgi?id=13352
1397 @system unittest
1398 {
1399     alias TP = Algebraic!(long);
1400     auto a = TP(1L);
1401     auto b = TP(2L);
1402     assert(!TP.allowed!ulong);
1403     assert(a + b == 3L);
1404     assert(a + 2 == 3L);
1405     assert(1 + b == 3L);
1406 
1407     alias TP2 = Algebraic!(long, string);
1408     auto c = TP2(3L);
1409     assert(a + c == 4L);
1410 }
1411 
1412 // https://issues.dlang.org/show_bug.cgi?id=13354
1413 @system unittest
1414 {
1415     alias A = Algebraic!(string[]);
1416     A a = ["a", "b"];
1417     assert(a[0] == "a");
1418     assert(a[1] == "b");
1419     a[1] = "c";
1420     assert(a[1] == "c");
1421 
1422     alias AA = Algebraic!(int[string]);
1423     AA aa = ["a": 1, "b": 2];
1424     assert(aa["a"] == 1);
1425     assert(aa["b"] == 2);
1426     aa["b"] = 3;
1427     assert(aa["b"] == 3);
1428 }
1429 
1430 // https://issues.dlang.org/show_bug.cgi?id=14198
1431 @system unittest
1432 {
1433     Variant a = true;
1434     assert(a.type == typeid(bool));
1435 }
1436 
1437 // https://issues.dlang.org/show_bug.cgi?id=14233
1438 @system unittest
1439 {
1440     alias Atom = Algebraic!(string, This[]);
1441 
1442     Atom[] values = [];
1443     auto a = Atom(values);
1444 }
1445 
1446 pure nothrow @nogc
1447 @system unittest
1448 {
1449     Algebraic!(int, double) a;
1450     a = 100;
1451     a = 1.0;
1452 }
1453 
1454 // https://issues.dlang.org/show_bug.cgi?id=14457
1455 @system unittest
1456 {
1457     alias A = Algebraic!(int, float, double);
1458     alias B = Algebraic!(int, float);
1459 
1460     A a = 1;
1461     B b = 6f;
1462     a = b;
1463 
1464     assert(a.type == typeid(float));
1465     assert(a.get!float == 6f);
1466 }
1467 
1468 // https://issues.dlang.org/show_bug.cgi?id=14585
1469 @system unittest
1470 {
1471     static struct S
1472     {
1473         int x = 42;
1474         ~this() {assert(x == 42);}
1475     }
1476     Variant(S()).get!S;
1477 }
1478 
1479 // https://issues.dlang.org/show_bug.cgi?id=14586
1480 @system unittest
1481 {
1482     const Variant v = new immutable Object;
1483     v.get!(immutable Object);
1484 }
1485 
1486 @system unittest
1487 {
1488     static struct S
1489     {
1490         T opCast(T)() {assert(false);}
1491     }
1492     Variant v = S();
1493     v.get!S;
1494 }
1495 
1496 // https://issues.dlang.org/show_bug.cgi?id=13262
1497 @system unittest
1498 {
1499     static void fun(T)(Variant v){
1500         T x;
1501         v = x;
1502         auto r = v.get!(T);
1503     }
1504     Variant v;
1505     fun!(shared(int))(v);
1506     fun!(shared(int)[])(v);
1507 
1508     static struct S1
1509     {
1510         int c;
1511         string a;
1512     }
1513 
1514     static struct S2
1515     {
1516         string a;
1517         shared int[] b;
1518     }
1519 
1520     static struct S3
1521     {
1522         string a;
1523         shared int[] b;
1524         int c;
1525     }
1526 
1527     fun!(S1)(v);
1528     fun!(shared(S1))(v);
1529     fun!(S2)(v);
1530     fun!(shared(S2))(v);
1531     fun!(S3)(v);
1532     fun!(shared(S3))(v);
1533 
1534     // ensure structs that are shared, but don't have shared postblits
1535     // can't be used.
1536     static struct S4
1537     {
1538         int x;
1539         this(this) {x = 0;}
1540     }
1541 
1542     fun!(S4)(v);
1543     static assert(!is(typeof(fun!(shared(S4))(v))));
1544 }
1545 
1546 @safe unittest
1547 {
1548     Algebraic!(int) x;
1549 
1550     static struct SafeS
1551     {
1552         @safe ~this() {}
1553     }
1554 
1555     Algebraic!(SafeS) y;
1556 }
1557 
1558 // https://issues.dlang.org/show_bug.cgi?id=19986
1559 @system unittest
1560 {
1561     VariantN!32 v;
1562     v = const(ubyte[33]).init;
1563 
1564     struct S
1565     {
1566         ubyte[33] s;
1567     }
1568 
1569     VariantN!32 v2;
1570     v2 = const(S).init;
1571 }
1572 
1573 // https://issues.dlang.org/show_bug.cgi?id=21021
1574 @system unittest
1575 {
1576     static struct S
1577     {
1578         int h;
1579         int[5] array;
1580         alias h this;
1581     }
1582 
1583     S msg;
1584     msg.array[] = 3;
1585     Variant a = msg;
1586     auto other = a.get!S;
1587     assert(msg.array[0] == 3);
1588     assert(other.array[0] == 3);
1589 }
1590 
1591 // https://issues.dlang.org/show_bug.cgi?id=21231
1592 // Compatibility with -preview=fieldwise
1593 @system unittest
1594 {
1595     static struct Empty
1596     {
1597         bool opCmp(const scope ref Empty) const
1598         { return false; }
1599     }
1600 
1601     Empty a, b;
1602     assert(a == b);
1603     assert(!(a < b));
1604 
1605     VariantN!(4, Empty) v = a;
1606     assert(v == b);
1607     assert(!(v < b));
1608 }
1609 
1610 // Compatibility with -preview=fieldwise
1611 @system unittest
1612 {
1613     static struct Empty
1614     {
1615         bool opEquals(const scope ref Empty) const
1616         { return false; }
1617     }
1618 
1619     Empty a, b;
1620     assert(a != b);
1621 
1622     VariantN!(4, Empty) v = a;
1623     assert(v != b);
1624 }
1625 
1626 // https://issues.dlang.org/show_bug.cgi?id=22647
1627 // Can compare with 'null'
1628 @system unittest
1629 {
1630     static struct Bar
1631     {
1632         int* ptr;
1633         alias ptr this;
1634     }
1635 
1636     static class Foo {}
1637     int* iptr;
1638     int[] arr;
1639 
1640     Variant v = Foo.init; // 'null'
1641     assert(v != null); // can only compare objects with 'null' by using 'is'
1642 
1643     v = iptr;
1644     assert(v == null); // pointers can be compared with 'null'
1645 
1646     v = arr;
1647     assert(v == null); // arrays can be compared with 'null'
1648 
1649     v = "";
1650     assert(v == null); // strings are arrays, an empty string is considered 'null'
1651 
1652     v = Bar.init;
1653     assert(v == null); // works with alias this
1654 
1655     v = [3];
1656     assert(v != null);
1657     assert(v > null);
1658     assert(v >= null);
1659     assert(!(v < null));
1660 }
1661 
1662 /**
1663 _Algebraic data type restricted to a closed set of possible
1664 types. It's an alias for $(LREF VariantN) with an
1665 appropriately-constructed maximum size. `Algebraic` is
1666 useful when it is desirable to restrict what a discriminated type
1667 could hold to the end of defining simpler and more efficient
1668 manipulation.
1669 
1670 $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
1671 code. Instead, use $(REF SumType, std,sumtype).)
1672 */
1673 template Algebraic(T...)
1674 {
1675     alias Algebraic = VariantN!(maxSize!T, T);
1676 }
1677 
1678 ///
1679 @system unittest
1680 {
1681     auto v = Algebraic!(int, double, string)(5);
1682     assert(v.peek!(int));
1683     v = 3.14;
1684     assert(v.peek!(double));
1685     // auto x = v.peek!(long); // won't compile, type long not allowed
1686     // v = '1'; // won't compile, type char not allowed
1687 }
1688 
1689 /**
1690 $(H4 Self-Referential Types)
1691 
1692 A useful and popular use of algebraic data structures is for defining $(LUCKY
1693 self-referential data structures), i.e. structures that embed references to
1694 values of their own type within.
1695 
1696 This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1697 reference to the type being defined is needed. The `Algebraic` instantiation
1698 will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1699 alpha renaming) on its constituent types, replacing `This`
1700 with the self-referenced type. The structure of the type involving `This` may
1701 be arbitrarily complex.
1702 */
1703 @system unittest
1704 {
1705     import std.typecons : Tuple, tuple;
1706 
1707     // A tree is either a leaf or a branch of two other trees
1708     alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
1709     Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
1710     Tree!int* right = tree.get!1[1];
1711     assert(*right == 43);
1712 
1713     // An object is a double, a string, or a hash of objects
1714     alias Obj = Algebraic!(double, string, This[string]);
1715     Obj obj = "hello";
1716     assert(obj.get!1 == "hello");
1717     obj = 42.0;
1718     assert(obj.get!0 == 42);
1719     obj = ["customer": Obj("John"), "paid": Obj(23.95)];
1720     assert(obj.get!2["customer"] == "John");
1721 }
1722 
1723 private struct FakeComplexReal
1724 {
1725     real re, im;
1726 }
1727 
1728 /**
1729 Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1730 `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1731 to hold all of D's predefined types unboxed, including all numeric types,
1732 pointers, delegates, and class references.  You may want to use
1733 `VariantN` directly with a different maximum size either for
1734 storing larger types unboxed, or for saving memory.
1735  */
1736 alias Variant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()));
1737 
1738 ///
1739 @system unittest
1740 {
1741     Variant a; // Must assign before use, otherwise exception ensues
1742     // Initialize with an integer; make the type int
1743     Variant b = 42;
1744     assert(b.type == typeid(int));
1745     // Peek at the value
1746     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1747     // Automatically convert per language rules
1748     auto x = b.get!(real);
1749 
1750     // Assign any other type, including other variants
1751     a = b;
1752     a = 3.14;
1753     assert(a.type == typeid(double));
1754     // Implicit conversions work just as with built-in types
1755     assert(a < b);
1756     // Check for convertibility
1757     assert(!a.convertsTo!(int)); // double not convertible to int
1758     // Strings and all other arrays are supported
1759     a = "now I'm a string";
1760     assert(a == "now I'm a string");
1761 }
1762 
1763 /// can also assign arrays
1764 @system unittest
1765 {
1766     Variant a = new int[42];
1767     assert(a.length == 42);
1768     a[5] = 7;
1769     assert(a[5] == 7);
1770 }
1771 
1772 /// Can also assign class values
1773 @system unittest
1774 {
1775     Variant a;
1776 
1777     class Foo {}
1778     auto foo = new Foo;
1779     a = foo;
1780     assert(*a.peek!(Foo) == foo); // and full type information is preserved
1781 }
1782 
1783 /**
1784  * Returns an array of variants constructed from `args`.
1785  *
1786  * This is by design. During construction the `Variant` needs
1787  * static type information about the type being held, so as to store a
1788  * pointer to function for fast retrieval.
1789  */
1790 Variant[] variantArray(T...)(T args)
1791 {
1792     Variant[] result;
1793     foreach (arg; args)
1794     {
1795         result ~= Variant(arg);
1796     }
1797     return result;
1798 }
1799 
1800 ///
1801 @system unittest
1802 {
1803     auto a = variantArray(1, 3.14, "Hi!");
1804     assert(a[1] == 3.14);
1805     auto b = Variant(a); // variant array as variant
1806     assert(b[1] == 3.14);
1807 }
1808 
1809 /**
1810  * Thrown in three cases:
1811  *
1812  * $(OL $(LI An uninitialized `Variant` is used in any way except
1813  * assignment and `hasValue`;) $(LI A `get` or
1814  * `coerce` is attempted with an incompatible target type;)
1815  * $(LI A comparison between `Variant` objects of
1816  * incompatible types is attempted.))
1817  *
1818  */
1819 
1820 // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
1821 static class VariantException : Exception
1822 {
1823     /// The source type in the conversion or comparison
1824     TypeInfo source;
1825     /// The target type in the conversion or comparison
1826     TypeInfo target;
1827     this(string s)
1828     {
1829         super(s);
1830     }
1831     this(TypeInfo source, TypeInfo target)
1832     {
1833         super("Variant: attempting to use incompatible types "
1834                             ~ source.toString()
1835                             ~ " and " ~ target.toString());
1836         this.source = source;
1837         this.target = target;
1838     }
1839 }
1840 
1841 ///
1842 @system unittest
1843 {
1844     import std.exception : assertThrown;
1845 
1846     Variant v;
1847 
1848     // uninitialized use
1849     assertThrown!VariantException(v + 1);
1850     assertThrown!VariantException(v.length);
1851 
1852     // .get with an incompatible target type
1853     assertThrown!VariantException(Variant("a").get!int);
1854 
1855     // comparison between incompatible types
1856     assertThrown!VariantException(Variant(3) < Variant("a"));
1857 }
1858 
1859 @system unittest
1860 {
1861     alias W1 = This2Variant!(char, int, This[int]);
1862     alias W2 = AliasSeq!(int, char[int]);
1863     static assert(is(W1 == W2));
1864 
1865     alias var_t = Algebraic!(void, string);
1866     var_t foo = "quux";
1867 }
1868 
1869 @system unittest
1870 {
1871      alias A = Algebraic!(real, This[], This[int], This[This]);
1872      A v1, v2, v3;
1873      v2 = 5.0L;
1874      v3 = 42.0L;
1875      //v1 = [ v2 ][];
1876       auto v = v1.peek!(A[]);
1877      //writeln(v[0]);
1878      v1 = [ 9 : v3 ];
1879      //writeln(v1);
1880      v1 = [ v3 : v3 ];
1881      //writeln(v1);
1882 }
1883 
1884 @system unittest
1885 {
1886     import std.conv : ConvException;
1887     import std.exception : assertThrown, collectException;
1888     // try it with an oddly small size
1889     VariantN!(1) test;
1890     assert(test.size > 1);
1891 
1892     // variantArray tests
1893     auto heterogeneous = variantArray(1, 4.5, "hi");
1894     assert(heterogeneous.length == 3);
1895     auto variantArrayAsVariant = Variant(heterogeneous);
1896     assert(variantArrayAsVariant[0] == 1);
1897     assert(variantArrayAsVariant.length == 3);
1898 
1899     // array tests
1900     auto arr = Variant([1.2].dup);
1901     auto e = arr[0];
1902     assert(e == 1.2);
1903     arr[0] = 2.0;
1904     assert(arr[0] == 2);
1905     arr ~= 4.5;
1906     assert(arr[1] == 4.5);
1907 
1908     // general tests
1909     Variant a;
1910     auto b = Variant(5);
1911     assert(!b.peek!(real) && b.peek!(int));
1912     // assign
1913     a = *b.peek!(int);
1914     // comparison
1915     assert(a == b, a.type.toString() ~ " " ~ b.type.toString());
1916     auto c = Variant("this is a string");
1917     assert(a != c);
1918     // comparison via implicit conversions
1919     a = 42; b = 42.0; assert(a == b);
1920 
1921     // try failing conversions
1922     bool failed = false;
1923     try
1924     {
1925         auto d = c.get!(int);
1926     }
1927     catch (Exception e)
1928     {
1929         //writeln(stderr, e.toString);
1930         failed = true;
1931     }
1932     assert(failed); // :o)
1933 
1934     // toString tests
1935     a = Variant(42); assert(a.toString() == "42");
1936     a = Variant(42.22); assert(a.toString() == "42.22");
1937 
1938     // coerce tests
1939     a = Variant(42.22); assert(a.coerce!(int) == 42);
1940     a = cast(short) 5; assert(a.coerce!(double) == 5);
1941     a = Variant("10"); assert(a.coerce!int == 10);
1942 
1943     a = Variant(1);
1944     assert(a.coerce!bool);
1945     a = Variant(0);
1946     assert(!a.coerce!bool);
1947 
1948     a = Variant(1.0);
1949     assert(a.coerce!bool);
1950     a = Variant(0.0);
1951     assert(!a.coerce!bool);
1952     a = Variant(float.init);
1953     assertThrown!ConvException(a.coerce!bool);
1954 
1955     a = Variant("true");
1956     assert(a.coerce!bool);
1957     a = Variant("false");
1958     assert(!a.coerce!bool);
1959     a = Variant("");
1960     assertThrown!ConvException(a.coerce!bool);
1961 
1962     // Object tests
1963     class B1 {}
1964     class B2 : B1 {}
1965     a = new B2;
1966     assert(a.coerce!(B1) !is null);
1967     a = new B1;
1968     assert(collectException(a.coerce!(B2) is null));
1969     a = cast(Object) new B2; // lose static type info; should still work
1970     assert(a.coerce!(B2) !is null);
1971 
1972 //     struct Big { int a[45]; }
1973 //     a = Big.init;
1974 
1975     // hash
1976     assert(a.toHash() != 0);
1977 }
1978 
1979 // tests adapted from
1980 // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601
1981 @system unittest
1982 {
1983     Variant v;
1984 
1985     assert(!v.hasValue);
1986     v = 42;
1987     assert( v.peek!(int) );
1988     assert( v.convertsTo!(long) );
1989     assert( v.get!(int) == 42 );
1990     assert( v.get!(long) == 42L );
1991     assert( v.get!(ulong) == 42uL );
1992 
1993     v = "Hello, World!";
1994     assert( v.peek!(string) );
1995 
1996     assert( v.get!(string) == "Hello, World!" );
1997     assert(!is(char[] : wchar[]));
1998     assert( !v.convertsTo!(wchar[]) );
1999     assert( v.get!(string) == "Hello, World!" );
2000 
2001     // Literal arrays are dynamically-typed
2002     v = cast(int[4]) [1,2,3,4];
2003     assert( v.peek!(int[4]) );
2004     assert( v.get!(int[4]) == [1,2,3,4] );
2005 
2006     {
2007          v = [1,2,3,4,5];
2008          assert( v.peek!(int[]) );
2009          assert( v.get!(int[]) == [1,2,3,4,5] );
2010     }
2011 
2012     v = 3.1413;
2013     assert( v.peek!(double) );
2014     assert( v.convertsTo!(real) );
2015     //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT
2016     assert( v.convertsTo!(float) );
2017     assert( *v.peek!(double) == 3.1413 );
2018 
2019     auto u = Variant(v);
2020     assert( u.peek!(double) );
2021     assert( *u.peek!(double) == 3.1413 );
2022 
2023     // operators
2024     v = 38;
2025     assert( v + 4 == 42 );
2026     assert( 4 + v == 42 );
2027     assert( v - 4 == 34 );
2028     assert( Variant(4) - v == -34 );
2029     assert( v * 2 == 76 );
2030     assert( 2 * v == 76 );
2031     assert( v / 2 == 19 );
2032     assert( Variant(2) / v == 0 );
2033     assert( v % 2 == 0 );
2034     assert( Variant(2) % v == 2 );
2035     assert( (v & 6) == 6 );
2036     assert( (6 & v) == 6 );
2037     assert( (v | 9) == 47 );
2038     assert( (9 | v) == 47 );
2039     assert( (v ^ 5) == 35 );
2040     assert( (5 ^ v) == 35 );
2041     assert( v << 1 == 76 );
2042     assert( Variant(1) << Variant(2) == 4 );
2043     assert( v >> 1 == 19 );
2044     assert( Variant(4) >> Variant(2) == 1 );
2045     assert( Variant("abc") ~ "def" == "abcdef" );
2046     assert( Variant("abc") ~ Variant("def") == "abcdef" );
2047 
2048     v = 38;
2049     v += 4;
2050     assert( v == 42 );
2051     v = 38; v -= 4; assert( v == 34 );
2052     v = 38; v *= 2; assert( v == 76 );
2053     v = 38; v /= 2; assert( v == 19 );
2054     v = 38; v %= 2; assert( v == 0 );
2055     v = 38; v &= 6; assert( v == 6 );
2056     v = 38; v |= 9; assert( v == 47 );
2057     v = 38; v ^= 5; assert( v == 35 );
2058     v = 38; v <<= 1; assert( v == 76 );
2059     v = 38; v >>= 1; assert( v == 19 );
2060     v = 38; v += 1;  assert( v < 40 );
2061 
2062     v = "abc";
2063     v ~= "def";
2064     assert( v == "abcdef", *v.peek!(char[]) );
2065     assert( Variant(0) < Variant(42) );
2066     assert( Variant(42) > Variant(0) );
2067     assert( Variant(42) > Variant(0.1) );
2068     assert( Variant(42.1) > Variant(1) );
2069     assert( Variant(21) == Variant(21) );
2070     assert( Variant(0) != Variant(42) );
2071     assert( Variant("bar") == Variant("bar") );
2072     assert( Variant("foo") != Variant("bar") );
2073 
2074     {
2075         auto v1 = Variant(42);
2076         auto v2 = Variant("foo");
2077 
2078         int[Variant] hash;
2079         hash[v1] = 0;
2080         hash[v2] = 1;
2081 
2082         assert( hash[v1] == 0 );
2083         assert( hash[v2] == 1 );
2084     }
2085 
2086     {
2087         int[char[]] hash;
2088         hash["a"] = 1;
2089         hash["b"] = 2;
2090         hash["c"] = 3;
2091         Variant vhash = hash;
2092 
2093         assert( vhash.get!(int[char[]])["a"] == 1 );
2094         assert( vhash.get!(int[char[]])["b"] == 2 );
2095         assert( vhash.get!(int[char[]])["c"] == 3 );
2096     }
2097 }
2098 
2099 @system unittest
2100 {
2101     // check comparisons incompatible with AllowedTypes
2102     Algebraic!int v = 2;
2103 
2104     assert(v == 2);
2105     assert(v < 3);
2106     static assert(!__traits(compiles, () => v == long.max));
2107     static assert(!__traits(compiles, () => v == null));
2108     static assert(!__traits(compiles, () => v < long.max));
2109     static assert(!__traits(compiles, () => v > null));
2110 }
2111 
2112 // https://issues.dlang.org/show_bug.cgi?id=1558
2113 @system unittest
2114 {
2115     Variant va=1;
2116     Variant vb=-2;
2117     assert((va+vb).get!(int) == -1);
2118     assert((va-vb).get!(int) == 3);
2119 }
2120 
2121 @system unittest
2122 {
2123     Variant a;
2124     a=5;
2125     Variant b;
2126     b=a;
2127     Variant[] c;
2128     c = variantArray(1, 2, 3.0, "hello", 4);
2129     assert(c[3] == "hello");
2130 }
2131 
2132 @system unittest
2133 {
2134     Variant v = 5;
2135     assert(!__traits(compiles, v.coerce!(bool delegate())));
2136 }
2137 
2138 
2139 @system unittest
2140 {
2141     struct Huge {
2142         real a, b, c, d, e, f, g;
2143     }
2144 
2145     Huge huge;
2146     huge.e = 42;
2147     Variant v;
2148     v = huge;  // Compile time error.
2149     assert(v.get!(Huge).e == 42);
2150 }
2151 
2152 @system unittest
2153 {
2154     const x = Variant(42);
2155     auto y1 = x.get!(const int);
2156     // @@@BUG@@@
2157     //auto y2 = x.get!(immutable int)();
2158 }
2159 
2160 // test iteration
2161 @system unittest
2162 {
2163     auto v = Variant([ 1, 2, 3, 4 ][]);
2164     auto j = 0;
2165     foreach (int i; v)
2166     {
2167         assert(i == ++j);
2168     }
2169     assert(j == 4);
2170 }
2171 
2172 // test convertibility
2173 @system unittest
2174 {
2175     auto v = Variant("abc".dup);
2176     assert(v.convertsTo!(char[]));
2177 }
2178 
2179 // https://issues.dlang.org/show_bug.cgi?id=5424
2180 @system unittest
2181 {
2182     interface A {
2183         void func1();
2184     }
2185     static class AC: A {
2186         void func1() {
2187         }
2188     }
2189 
2190     A a = new AC();
2191     a.func1();
2192     Variant b = Variant(a);
2193 }
2194 
2195 // https://issues.dlang.org/show_bug.cgi?id=7070
2196 @system unittest
2197 {
2198     Variant v;
2199     v = null;
2200 }
2201 
2202 // Class and interface opEquals, https://issues.dlang.org/show_bug.cgi?id=12157
2203 @system unittest
2204 {
2205     class Foo { }
2206 
2207     class DerivedFoo : Foo { }
2208 
2209     Foo f1 = new Foo();
2210     Foo f2 = new DerivedFoo();
2211 
2212     Variant v1 = f1, v2 = f2;
2213     assert(v1 == f1);
2214     assert(v1 != new Foo());
2215     assert(v1 != f2);
2216     assert(v2 != v1);
2217     assert(v2 == f2);
2218 }
2219 
2220 // Const parameters with opCall, https://issues.dlang.org/show_bug.cgi?id=11361
2221 @system unittest
2222 {
2223     static string t1(string c) {
2224         return c ~ "a";
2225     }
2226 
2227     static const(char)[] t2(const(char)[] p) {
2228         return p ~ "b";
2229     }
2230 
2231     static char[] t3(int p) {
2232         import std.conv : text;
2233         return p.text.dup;
2234     }
2235 
2236     Variant v1 = &t1;
2237     Variant v2 = &t2;
2238     Variant v3 = &t3;
2239 
2240     assert(v1("abc") == "abca");
2241     assert(v1("abc").type == typeid(string));
2242     assert(v2("abc") == "abcb");
2243 
2244     assert(v2(cast(char[])("abc".dup)) == "abcb");
2245     assert(v2("abc").type == typeid(const(char)[]));
2246 
2247     assert(v3(4) == ['4']);
2248     assert(v3(4).type == typeid(char[]));
2249 }
2250 
2251 // https://issues.dlang.org/show_bug.cgi?id=12071
2252 @system unittest
2253 {
2254     static struct Structure { int data; }
2255     alias VariantTest = Algebraic!(Structure delegate() pure nothrow @nogc @safe);
2256 
2257     bool called = false;
2258     Structure example() pure nothrow @nogc @safe
2259     {
2260         called = true;
2261         return Structure.init;
2262     }
2263     auto m = VariantTest(&example);
2264     m();
2265     assert(called);
2266 }
2267 
2268 // Ordering comparisons of incompatible types
2269 // e.g. https://issues.dlang.org/show_bug.cgi?id=7990
2270 @system unittest
2271 {
2272     import std.exception : assertThrown;
2273     assertThrown!VariantException(Variant(3) < "a");
2274     assertThrown!VariantException("a" < Variant(3));
2275     assertThrown!VariantException(Variant(3) < Variant("a"));
2276 
2277     assertThrown!VariantException(Variant.init < Variant(3));
2278     assertThrown!VariantException(Variant(3) < Variant.init);
2279 }
2280 
2281 // Handling of unordered types
2282 // https://issues.dlang.org/show_bug.cgi?id=9043
2283 @system unittest
2284 {
2285     import std.exception : assertThrown;
2286     static struct A { int a; }
2287 
2288     assert(Variant(A(3)) != A(4));
2289 
2290     assertThrown!VariantException(Variant(A(3)) < A(4));
2291     assertThrown!VariantException(A(3) < Variant(A(4)));
2292     assertThrown!VariantException(Variant(A(3)) < Variant(A(4)));
2293 }
2294 
2295 // Handling of empty types and arrays
2296 // https://issues.dlang.org/show_bug.cgi?id=10958
2297 @system unittest
2298 {
2299     class EmptyClass { }
2300     struct EmptyStruct { }
2301     alias EmptyArray = void[0];
2302     alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray);
2303 
2304     Variant testEmpty(T)()
2305     {
2306         T inst;
2307         Variant v = inst;
2308         assert(v.get!T == inst);
2309         assert(v.peek!T !is null);
2310         assert(*v.peek!T == inst);
2311         Alg alg = inst;
2312         assert(alg.get!T == inst);
2313         return v;
2314     }
2315 
2316     testEmpty!EmptyClass();
2317     testEmpty!EmptyStruct();
2318     testEmpty!EmptyArray();
2319 
2320     // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0.
2321     EmptyArray arr = EmptyArray.init;
2322     Algebraic!(EmptyArray) a = arr;
2323     assert(a.length == 0);
2324     assert(a.get!EmptyArray == arr);
2325 }
2326 
2327 // Handling of void function pointers / delegates
2328 // https://issues.dlang.org/show_bug.cgi?id=11360
2329 @system unittest
2330 {
2331     static void t1() { }
2332     Variant v = &t1;
2333     assert(v() == Variant.init);
2334 
2335     static int t2() { return 3; }
2336     Variant v2 = &t2;
2337     assert(v2() == 3);
2338 }
2339 
2340 // Using peek for large structs
2341 // https://issues.dlang.org/show_bug.cgi?id=8580
2342 @system unittest
2343 {
2344     struct TestStruct(bool pad)
2345     {
2346         int val1;
2347         static if (pad)
2348             ubyte[Variant.size] padding;
2349         int val2;
2350     }
2351 
2352     void testPeekWith(T)()
2353     {
2354         T inst;
2355         inst.val1 = 3;
2356         inst.val2 = 4;
2357         Variant v = inst;
2358         T* original = v.peek!T;
2359         assert(original.val1 == 3);
2360         assert(original.val2 == 4);
2361         original.val1 = 6;
2362         original.val2 = 8;
2363         T modified = v.get!T;
2364         assert(modified.val1 == 6);
2365         assert(modified.val2 == 8);
2366     }
2367 
2368     testPeekWith!(TestStruct!false)();
2369     testPeekWith!(TestStruct!true)();
2370 }
2371 
2372 // https://issues.dlang.org/show_bug.cgi?id=18780
2373 @system unittest
2374 {
2375     int x = 7;
2376     Variant a = x;
2377     assert(a.convertsTo!ulong);
2378     assert(a.convertsTo!uint);
2379 }
2380 
2381 /**
2382  * Applies a delegate or function to the given $(LREF Algebraic) depending on the held type,
2383  * ensuring that all types are handled by the visiting functions.
2384  *
2385  * The delegate or function having the currently held value as parameter is called
2386  * with `variant`'s current value. Visiting handlers are passed
2387  * in the template parameter list.
2388  * It is statically ensured that all held types of
2389  * `variant` are handled across all handlers.
2390  * `visit` allows delegates and static functions to be passed
2391  * as parameters.
2392  *
2393  * If a function with an untyped parameter is specified, this function is called
2394  * when the variant contains a type that does not match any other function.
2395  * This can be used to apply the same function across multiple possible types.
2396  * Exactly one generic function is allowed.
2397  *
2398  * If a function without parameters is specified, this function is called
2399  * when `variant` doesn't hold a value. Exactly one parameter-less function
2400  * is allowed.
2401  *
2402  * Duplicate overloads matching the same type in one of the visitors are disallowed.
2403  *
2404  * Returns: The return type of visit is deduced from the visiting functions and must be
2405  * the same across all overloads.
2406  * Throws: $(LREF VariantException) if `variant` doesn't hold a value and no
2407  * parameter-less fallback function is specified.
2408  */
2409 template visit(Handlers...)
2410 if (Handlers.length > 0)
2411 {
2412     ///
2413     auto visit(VariantType)(VariantType variant)
2414     if (isAlgebraic!VariantType)
2415     {
2416         return visitImpl!(true, VariantType, Handlers)(variant);
2417     }
2418 }
2419 
2420 ///
2421 @system unittest
2422 {
2423     Algebraic!(int, string) variant;
2424 
2425     variant = 10;
2426     assert(variant.visit!((string s) => cast(int) s.length,
2427                           (int i)    => i)()
2428                           == 10);
2429     variant = "string";
2430     assert(variant.visit!((int i) => i,
2431                           (string s) => cast(int) s.length)()
2432                           == 6);
2433 
2434     // Error function usage
2435     Algebraic!(int, string) emptyVar;
2436     auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
2437                           (int i)    => i,
2438                           () => -1)();
2439     assert(rslt == -1);
2440 
2441     // Generic function usage
2442     Algebraic!(int, float, real) number = 2;
2443     assert(number.visit!(x => x += 1) == 3);
2444 
2445     // Generic function for int/float with separate behavior for string
2446     Algebraic!(int, float, string) something = 2;
2447     assert(something.visit!((string s) => s.length, x => x) == 2); // generic
2448     something = "asdf";
2449     assert(something.visit!((string s) => s.length, x => x) == 4); // string
2450 
2451     // Generic handler and empty handler
2452     Algebraic!(int, float, real) empty2;
2453     assert(empty2.visit!(x => x + 1, () => -1) == -1);
2454 }
2455 
2456 @system unittest
2457 {
2458     Algebraic!(size_t, string) variant;
2459 
2460     // not all handled check
2461     static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
2462 
2463     variant = cast(size_t) 10;
2464     auto which = 0;
2465     variant.visit!( (string s) => which = 1,
2466                     (size_t i) => which = 0
2467                     )();
2468 
2469     // integer overload was called
2470     assert(which == 0);
2471 
2472     // mustn't compile as generic Variant not supported
2473     Variant v;
2474     static assert(!__traits(compiles, v.visit!((string s) => which = 1,
2475                                                (size_t i) => which = 0
2476                                                 )()
2477                                                 ));
2478 
2479     static size_t func(string s) {
2480         return s.length;
2481     }
2482 
2483     variant = "test";
2484     assert( 4 == variant.visit!(func,
2485                                 (size_t i) => i
2486                                 )());
2487 
2488     Algebraic!(int, float, string) variant2 = 5.0f;
2489     // Shouldn' t compile as float not handled by visitor.
2490     static assert(!__traits(compiles, variant2.visit!(
2491                         (int _) {},
2492                         (string _) {})()));
2493 
2494     Algebraic!(size_t, string, float) variant3;
2495     variant3 = 10.0f;
2496     auto floatVisited = false;
2497 
2498     assert(variant3.visit!(
2499                  (float f) { floatVisited = true; return cast(size_t) f; },
2500                  func,
2501                  (size_t i) { return i; }
2502                  )() == 10);
2503     assert(floatVisited == true);
2504 
2505     Algebraic!(float, string) variant4;
2506 
2507     assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
2508 
2509     // double error func check
2510     static assert(!__traits(compiles,
2511                             visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
2512                  );
2513 }
2514 
2515 // disallow providing multiple generic handlers to visit
2516 // disallow a generic handler that does not apply to all types
2517 @system unittest
2518 {
2519     Algebraic!(int, float) number = 2;
2520     // ok, x + 1 valid for int and float
2521     static assert( __traits(compiles, number.visit!(x => x + 1)));
2522     // bad, two generic handlers
2523     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
2524     // bad, x ~ "a" does not apply to int or float
2525     static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2526     // bad, x ~ "a" does not apply to int or float
2527     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2528 
2529     Algebraic!(int, string) maybenumber = 2;
2530     // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
2531     static assert( __traits(compiles, maybenumber.visit!((string x) => x ~ "a", x => "foobar"[0 .. x + 1])));
2532     // bad, x ~ "a" valid for string but not int
2533     static assert(!__traits(compiles, maybenumber.visit!(x => x ~ "a")));
2534     // bad, two generics, each only applies in one case
2535     static assert(!__traits(compiles, maybenumber.visit!(x => x + 1, x => x ~ "a")));
2536 }
2537 
2538 /**
2539  * Behaves as $(LREF visit) but doesn't enforce that all types are handled
2540  * by the visiting functions.
2541  *
2542  * If a parameter-less function is specified it is called when
2543  * either `variant` doesn't hold a value or holds a type
2544  * which isn't handled by the visiting functions.
2545  *
2546  * Returns: The return type of tryVisit is deduced from the visiting functions and must be
2547  * the same across all overloads.
2548  * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
2549  * `variant` holds a value which isn't handled by the visiting functions,
2550  * when no parameter-less fallback function is specified.
2551  */
2552 template tryVisit(Handlers...)
2553 if (Handlers.length > 0)
2554 {
2555     ///
2556     auto tryVisit(VariantType)(VariantType variant)
2557     if (isAlgebraic!VariantType)
2558     {
2559         return visitImpl!(false, VariantType, Handlers)(variant);
2560     }
2561 }
2562 
2563 ///
2564 @system unittest
2565 {
2566     Algebraic!(int, string) variant;
2567 
2568     variant = 10;
2569     auto which = -1;
2570     variant.tryVisit!((int i) { which = 0; })();
2571     assert(which == 0);
2572 
2573     // Error function usage
2574     variant = "test";
2575     variant.tryVisit!((int i) { which = 0; },
2576                       ()      { which = -100; })();
2577     assert(which == -100);
2578 }
2579 
2580 @system unittest
2581 {
2582     import std.exception : assertThrown;
2583     Algebraic!(int, string) variant;
2584 
2585     variant = 10;
2586     auto which = -1;
2587     variant.tryVisit!((int i){ which = 0; })();
2588 
2589     assert(which == 0);
2590 
2591     variant = "test";
2592 
2593     assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
2594 
2595     void errorfunc()
2596     {
2597         which = -1;
2598     }
2599 
2600     variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2601 
2602     assert(which == -1);
2603 }
2604 
2605 private template isAlgebraic(Type)
2606 {
2607     static if (is(Type _ == VariantN!T, T...))
2608         enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
2609     else
2610         enum isAlgebraic = false;
2611 }
2612 
2613 @system unittest
2614 {
2615     static assert(!isAlgebraic!(Variant));
2616     static assert( isAlgebraic!(Algebraic!(string)));
2617     static assert( isAlgebraic!(Algebraic!(int, int[])));
2618 }
2619 
2620 private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2621 if (isAlgebraic!VariantType && Handler.length > 0)
2622 {
2623     alias AllowedTypes = VariantType.AllowedTypes;
2624 
2625 
2626     /**
2627      * Returns: Struct where `indices`  is an array which
2628      * contains at the n-th position the index in Handler which takes the
2629      * n-th type of AllowedTypes. If an Handler doesn't match an
2630      * AllowedType, -1 is set. If a function in the delegates doesn't
2631      * have parameters, the field `exceptionFuncIdx` is set;
2632      * otherwise it's -1.
2633      */
2634     auto visitGetOverloadMap()
2635     {
2636         struct Result {
2637             int[AllowedTypes.length] indices;
2638             int exceptionFuncIdx = -1;
2639             int generalFuncIdx = -1;
2640         }
2641 
2642         Result result;
2643 
2644         enum int nonmatch = ()
2645         {
2646             foreach (int dgidx, dg; Handler)
2647             {
2648                 bool found = false;
2649                 foreach (T; AllowedTypes)
2650                 {
2651                     found |= __traits(compiles, { static assert(isSomeFunction!(dg!T)); });
2652                     found |= __traits(compiles, (T t) { dg(t); });
2653                     found |= __traits(compiles, dg());
2654                 }
2655                 if (!found) return dgidx;
2656             }
2657             return -1;
2658         }();
2659         static assert(nonmatch == -1, "No match for visit handler #"~
2660             nonmatch.stringof~" ("~Handler[nonmatch].stringof~")");
2661 
2662         foreach (tidx, T; AllowedTypes)
2663         {
2664             bool added = false;
2665             foreach (dgidx, dg; Handler)
2666             {
2667                 // Handle normal function objects
2668                 static if (isSomeFunction!dg)
2669                 {
2670                     alias Params = Parameters!dg;
2671                     static if (Params.length == 0)
2672                     {
2673                         // Just check exception functions in the first
2674                         // inner iteration (over delegates)
2675                         if (tidx > 0)
2676                             continue;
2677                         else
2678                         {
2679                             if (result.exceptionFuncIdx != -1)
2680                                 assert(false, "duplicate parameter-less (error-)function specified");
2681                             result.exceptionFuncIdx = dgidx;
2682                         }
2683                     }
2684                     else static if (is(Params[0] == T) || is(Unqual!(Params[0]) == T))
2685                     {
2686                         if (added)
2687                             assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'");
2688 
2689                         added = true;
2690                         result.indices[tidx] = dgidx;
2691                     }
2692                 }
2693                 else static if (__traits(compiles, { static assert(isSomeFunction!(dg!T)); }))
2694                 {
2695                     assert(result.generalFuncIdx == -1 ||
2696                            result.generalFuncIdx == dgidx,
2697                            "Only one generic visitor function is allowed");
2698                     result.generalFuncIdx = dgidx;
2699                 }
2700                 // Handle composite visitors with opCall overloads
2701             }
2702 
2703             if (!added)
2704                 result.indices[tidx] = -1;
2705         }
2706 
2707         return result;
2708     }
2709 
2710     enum HandlerOverloadMap = visitGetOverloadMap();
2711 
2712     if (!variant.hasValue)
2713     {
2714         // Call the exception function. The HandlerOverloadMap
2715         // will have its exceptionFuncIdx field set to value != -1 if an
2716         // exception function has been specified; otherwise we just through an exception.
2717         static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2718             return Handler[ HandlerOverloadMap.exceptionFuncIdx ]();
2719         else
2720             throw new VariantException("variant must hold a value before being visited.");
2721     }
2722 
2723     foreach (idx, T; AllowedTypes)
2724     {
2725         if (auto ptr = variant.peek!T)
2726         {
2727             enum dgIdx = HandlerOverloadMap.indices[idx];
2728 
2729             static if (dgIdx == -1)
2730             {
2731                 static if (HandlerOverloadMap.generalFuncIdx >= 0)
2732                     return Handler[HandlerOverloadMap.generalFuncIdx](*ptr);
2733                 else static if (Strict)
2734                     static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified");
2735                 else static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2736                     return Handler[HandlerOverloadMap.exceptionFuncIdx]();
2737                 else
2738                     throw new VariantException(
2739                         "variant holds value of type '"
2740                         ~ T.stringof ~
2741                         "' but no visitor has been provided"
2742                     );
2743             }
2744             else
2745             {
2746                 return Handler[ dgIdx ](*ptr);
2747             }
2748         }
2749     }
2750 
2751     assert(false);
2752 }
2753 
2754 // https://issues.dlang.org/show_bug.cgi?id=21253
2755 @system unittest
2756 {
2757     static struct A { int n; }
2758     static struct B {        }
2759 
2760     auto a = Algebraic!(A, B)(B());
2761     assert(a.visit!(
2762         (B _) => 42,
2763         (a  ) => a.n
2764     ) == 42);
2765 }
2766 
2767 @system unittest
2768 {
2769     // validate that visit can be called with a const type
2770     struct Foo { int depth; }
2771     struct Bar { int depth; }
2772     alias FooBar = Algebraic!(Foo, Bar);
2773 
2774     int depth(in FooBar fb) {
2775         return fb.visit!((Foo foo) => foo.depth,
2776                          (Bar bar) => bar.depth);
2777     }
2778 
2779     FooBar fb = Foo(3);
2780     assert(depth(fb) == 3);
2781 }
2782 
2783 // https://issues.dlang.org/show_bug.cgi?id=16383
2784 @system unittest
2785 {
2786     class Foo {this() immutable {}}
2787     alias V = Algebraic!(immutable Foo);
2788 
2789     auto x = V(new immutable Foo).visit!(
2790         (immutable(Foo) _) => 3
2791     );
2792     assert(x == 3);
2793 }
2794 
2795 // https://issues.dlang.org/show_bug.cgi?id=5310
2796 @system unittest
2797 {
2798     const Variant a;
2799     assert(a == a);
2800     Variant b;
2801     assert(a == b);
2802     assert(b == a);
2803 }
2804 
2805 @system unittest
2806 {
2807     const Variant a = [2];
2808     assert(a[0] == 2);
2809 }
2810 
2811 // https://issues.dlang.org/show_bug.cgi?id=10017
2812 @system unittest
2813 {
2814     static struct S
2815     {
2816         ubyte[Variant.size + 1] s;
2817     }
2818 
2819     Variant v1, v2;
2820     v1 = S(); // the payload is allocated on the heap
2821     v2 = v1;  // AssertError: target must be non-null
2822     assert(v1 == v2);
2823 }
2824 
2825 // https://issues.dlang.org/show_bug.cgi?id=7069
2826 @system unittest
2827 {
2828     import std.exception : assertThrown;
2829     Variant v;
2830 
2831     int i = 10;
2832     v = i;
2833     static foreach (qual; AliasSeq!(Alias, ConstOf))
2834     {
2835         assert(v.get!(qual!int) == 10);
2836         assert(v.get!(qual!float) == 10.0f);
2837     }
2838     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2839     {
2840         assertThrown!VariantException(v.get!(qual!int));
2841     }
2842 
2843     const(int) ci = 20;
2844     v = ci;
2845     static foreach (qual; AliasSeq!(ConstOf))
2846     {
2847         assert(v.get!(qual!int) == 20);
2848         assert(v.get!(qual!float) == 20.0f);
2849     }
2850     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2851     {
2852         assertThrown!VariantException(v.get!(qual!int));
2853         assertThrown!VariantException(v.get!(qual!float));
2854     }
2855 
2856     immutable(int) ii = ci;
2857     v = ii;
2858     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2859     {
2860         assert(v.get!(qual!int) == 20);
2861         assert(v.get!(qual!float) == 20.0f);
2862     }
2863     static foreach (qual; AliasSeq!(Alias, SharedOf))
2864     {
2865         assertThrown!VariantException(v.get!(qual!int));
2866         assertThrown!VariantException(v.get!(qual!float));
2867     }
2868 
2869     int[] ai = [1,2,3];
2870     v = ai;
2871     static foreach (qual; AliasSeq!(Alias, ConstOf))
2872     {
2873         assert(v.get!(qual!(int[])) == [1,2,3]);
2874         assert(v.get!(qual!(int)[]) == [1,2,3]);
2875     }
2876     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2877     {
2878         assertThrown!VariantException(v.get!(qual!(int[])));
2879         assertThrown!VariantException(v.get!(qual!(int)[]));
2880     }
2881 
2882     const(int[]) cai = [4,5,6];
2883     v = cai;
2884     static foreach (qual; AliasSeq!(ConstOf))
2885     {
2886         assert(v.get!(qual!(int[])) == [4,5,6]);
2887         assert(v.get!(qual!(int)[]) == [4,5,6]);
2888     }
2889     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2890     {
2891         assertThrown!VariantException(v.get!(qual!(int[])));
2892         assertThrown!VariantException(v.get!(qual!(int)[]));
2893     }
2894 
2895     immutable(int[]) iai = [7,8,9];
2896     v = iai;
2897     //assert(v.get!(immutable(int[])) == [7,8,9]);   // Bug ??? runtime error
2898     assert(v.get!(immutable(int)[]) == [7,8,9]);
2899     assert(v.get!(const(int[])) == [7,8,9]);
2900     assert(v.get!(const(int)[]) == [7,8,9]);
2901     //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2902     //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2903     static foreach (qual; AliasSeq!(Alias))
2904     {
2905         assertThrown!VariantException(v.get!(qual!(int[])));
2906         assertThrown!VariantException(v.get!(qual!(int)[]));
2907     }
2908 
2909     class A {}
2910     class B : A {}
2911     B b = new B();
2912     v = b;
2913     static foreach (qual; AliasSeq!(Alias, ConstOf))
2914     {
2915         assert(v.get!(qual!B) is b);
2916         assert(v.get!(qual!A) is b);
2917         assert(v.get!(qual!Object) is b);
2918     }
2919     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2920     {
2921         assertThrown!VariantException(v.get!(qual!B));
2922         assertThrown!VariantException(v.get!(qual!A));
2923         assertThrown!VariantException(v.get!(qual!Object));
2924     }
2925 
2926     const(B) cb = new B();
2927     v = cb;
2928     static foreach (qual; AliasSeq!(ConstOf))
2929     {
2930         assert(v.get!(qual!B) is cb);
2931         assert(v.get!(qual!A) is cb);
2932         assert(v.get!(qual!Object) is cb);
2933     }
2934     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2935     {
2936         assertThrown!VariantException(v.get!(qual!B));
2937         assertThrown!VariantException(v.get!(qual!A));
2938         assertThrown!VariantException(v.get!(qual!Object));
2939     }
2940 
2941     immutable(B) ib = new immutable(B)();
2942     v = ib;
2943     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2944     {
2945         assert(v.get!(qual!B) is ib);
2946         assert(v.get!(qual!A) is ib);
2947         assert(v.get!(qual!Object) is ib);
2948     }
2949     static foreach (qual; AliasSeq!(Alias, SharedOf))
2950     {
2951         assertThrown!VariantException(v.get!(qual!B));
2952         assertThrown!VariantException(v.get!(qual!A));
2953         assertThrown!VariantException(v.get!(qual!Object));
2954     }
2955 
2956     shared(B) sb = new shared B();
2957     v = sb;
2958     static foreach (qual; AliasSeq!(SharedOf, SharedConstOf))
2959     {
2960         assert(v.get!(qual!B) is sb);
2961         assert(v.get!(qual!A) is sb);
2962         assert(v.get!(qual!Object) is sb);
2963     }
2964     static foreach (qual; AliasSeq!(Alias, ImmutableOf, ConstOf))
2965     {
2966         assertThrown!VariantException(v.get!(qual!B));
2967         assertThrown!VariantException(v.get!(qual!A));
2968         assertThrown!VariantException(v.get!(qual!Object));
2969     }
2970 
2971     shared(const(B)) scb = new shared const B();
2972     v = scb;
2973     static foreach (qual; AliasSeq!(SharedConstOf))
2974     {
2975         assert(v.get!(qual!B) is scb);
2976         assert(v.get!(qual!A) is scb);
2977         assert(v.get!(qual!Object) is scb);
2978     }
2979     static foreach (qual; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf))
2980     {
2981         assertThrown!VariantException(v.get!(qual!B));
2982         assertThrown!VariantException(v.get!(qual!A));
2983         assertThrown!VariantException(v.get!(qual!Object));
2984     }
2985 }
2986 
2987 // https://issues.dlang.org/show_bug.cgi?id=12540
2988 @system unittest
2989 {
2990     static struct DummyScope
2991     {
2992         alias Alias12540 = Algebraic!Class12540;
2993 
2994         static class Class12540
2995         {
2996             Alias12540 entity;
2997         }
2998     }
2999 }
3000 
3001 @system unittest
3002 {
3003     // https://issues.dlang.org/show_bug.cgi?id=10194
3004     // Also test for elaborate copying
3005     static struct S
3006     {
3007         @disable this();
3008         this(int dummy)
3009         {
3010             ++cnt;
3011         }
3012 
3013         this(this)
3014         {
3015             ++cnt;
3016         }
3017 
3018         @disable S opAssign();
3019 
3020         ~this()
3021         {
3022             --cnt;
3023             assert(cnt >= 0);
3024         }
3025         static int cnt = 0;
3026     }
3027 
3028     {
3029         Variant v;
3030         {
3031             v = S(0);
3032             assert(S.cnt == 1);
3033         }
3034         assert(S.cnt == 1);
3035 
3036         // assigning a new value should destroy the existing one
3037         v = 0;
3038         assert(S.cnt == 0);
3039 
3040         // destroying the variant should destroy it's current value
3041         v = S(0);
3042         assert(S.cnt == 1);
3043     }
3044     assert(S.cnt == 0);
3045 }
3046 
3047 @system unittest
3048 {
3049     // https://issues.dlang.org/show_bug.cgi?id=13300
3050     static struct S
3051     {
3052         this(this) {}
3053         ~this() {}
3054     }
3055 
3056     static assert( hasElaborateCopyConstructor!(Variant));
3057     static assert(!hasElaborateCopyConstructor!(Algebraic!bool));
3058     static assert( hasElaborateCopyConstructor!(Algebraic!S));
3059     static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S)));
3060 
3061     static assert( hasElaborateDestructor!(Variant));
3062     static assert(!hasElaborateDestructor!(Algebraic!bool));
3063     static assert( hasElaborateDestructor!(Algebraic!S));
3064     static assert( hasElaborateDestructor!(Algebraic!(bool, S)));
3065 
3066     import std.array;
3067     alias Value = Algebraic!bool;
3068 
3069     static struct T
3070     {
3071         Value value;
3072         @disable this();
3073     }
3074     auto a = appender!(T[]);
3075 }
3076 
3077 // https://issues.dlang.org/show_bug.cgi?id=13871
3078 @system unittest
3079 {
3080     alias A = Algebraic!(int, typeof(null));
3081     static struct B { A value; }
3082     alias C = std.variant.Algebraic!B;
3083 
3084     C var;
3085     var = C(B());
3086 }
3087 
3088 @system unittest
3089 {
3090     import std.exception : assertThrown, assertNotThrown;
3091     // Make sure Variant can handle types with opDispatch but no length field.
3092     struct SWithNoLength
3093     {
3094         void opDispatch(string s)() { }
3095     }
3096 
3097     struct SWithLength
3098     {
3099         @property int opDispatch(string s)()
3100         {
3101             // Assume that s == "length"
3102             return 5; // Any value is OK for test.
3103         }
3104     }
3105 
3106     SWithNoLength sWithNoLength;
3107     Variant v = sWithNoLength;
3108     assertThrown!VariantException(v.length);
3109 
3110     SWithLength sWithLength;
3111     v = sWithLength;
3112     assertNotThrown!VariantException(v.get!SWithLength.length);
3113     assertThrown!VariantException(v.length);
3114 }
3115 
3116 // https://issues.dlang.org/show_bug.cgi?id=13534
3117 @system unittest
3118 {
3119     static assert(!__traits(compiles, () @safe {
3120         auto foo() @system { return 3; }
3121         auto v = Variant(&foo);
3122         v(); // foo is called in safe code!?
3123     }));
3124 }
3125 
3126 // https://issues.dlang.org/show_bug.cgi?id=15039
3127 @system unittest
3128 {
3129     import std.typecons;
3130     import std.variant;
3131 
3132     alias IntTypedef = Typedef!int;
3133     alias Obj = Algebraic!(int, IntTypedef, This[]);
3134 
3135     Obj obj = 1;
3136 
3137     obj.visit!(
3138         (int x) {},
3139         (IntTypedef x) {},
3140         (Obj[] x) {},
3141     );
3142 }
3143 
3144 // https://issues.dlang.org/show_bug.cgi?id=15791
3145 @system unittest
3146 {
3147     int n = 3;
3148     struct NS1 { int foo() { return n + 10; } }
3149     struct NS2 { int foo() { return n * 10; } }
3150 
3151     Variant v;
3152     v = NS1();
3153     assert(v.get!NS1.foo() == 13);
3154     v = NS2();
3155     assert(v.get!NS2.foo() == 30);
3156 }
3157 
3158 // https://issues.dlang.org/show_bug.cgi?id=15827
3159 @system unittest
3160 {
3161     static struct Foo15827 { Variant v; this(Foo15827 v) {} }
3162     Variant v = Foo15827.init;
3163 }
3164 
3165 // https://issues.dlang.org/show_bug.cgi?id=18934
3166 @system unittest
3167 {
3168     static struct S
3169     {
3170         const int x;
3171     }
3172 
3173     auto s = S(42);
3174     Variant v = s;
3175     auto s2 = v.get!S;
3176     assert(s2.x == 42);
3177     Variant v2 = v; // support copying from one variant to the other
3178     v2 = S(2);
3179     v = v2;
3180     assert(v.get!S.x == 2);
3181 }
3182 
3183 // https://issues.dlang.org/show_bug.cgi?id=19200
3184 @system unittest
3185 {
3186     static struct S
3187     {
3188         static int opBinaryRight(string op : "|", T)(T rhs)
3189         {
3190             return 3;
3191         }
3192     }
3193 
3194     S s;
3195     Variant v;
3196     auto b = v | s;
3197     assert(b == 3);
3198 }
3199 
3200 // https://issues.dlang.org/show_bug.cgi?id=11061
3201 @system unittest
3202 {
3203     int[4] el = [0, 1, 2, 3];
3204     int[3] nl = [0, 1, 2];
3205     Variant v1 = el;
3206     assert(v1 == el); // Compare Var(static) to static
3207     assert(v1 != nl); // Compare static arrays of different length
3208     assert(v1 == [0, 1, 2, 3]); // Compare Var(static) to dynamic.
3209     assert(v1 != [0, 1, 2]);
3210     int[] dyn = [0, 1, 2, 3];
3211     v1 = dyn;
3212     assert(v1 == el); // Compare Var(dynamic) to static.
3213     assert(v1 == [0, 1] ~ [2, 3]); // Compare Var(dynamic) to dynamic
3214 }
3215 
3216 // https://issues.dlang.org/show_bug.cgi?id=15940
3217 @system unittest
3218 {
3219     class C { }
3220     struct S
3221     {
3222         C a;
3223         alias a this;
3224     }
3225     S s = S(new C());
3226     auto v = Variant(s); // compile error
3227 }
3228 
3229 @system unittest
3230 {
3231     // Test if we don't have scoping issues.
3232     Variant createVariant(int[] input)
3233     {
3234         int[2] el = [input[0], input[1]];
3235         Variant v = el;
3236         return v;
3237     }
3238     Variant v = createVariant([0, 1]);
3239     createVariant([2, 3]);
3240     assert(v == [0,1]);
3241 }
3242 
3243 // https://issues.dlang.org/show_bug.cgi?id=19994
3244 @safe unittest
3245 {
3246     alias Inner = Algebraic!(This*);
3247     alias Outer = Algebraic!(Inner, This*);
3248 
3249     static assert(is(Outer.AllowedTypes == AliasSeq!(Inner, Outer*)));
3250 }
3251 
3252 // https://issues.dlang.org/show_bug.cgi?id=21296
3253 @system unittest
3254 {
3255     immutable aa = ["0": 0];
3256     auto v = Variant(aa); // compile error
3257 }