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