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