xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/src/std/variant.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg // Written in the D programming language.
2181254a7Smrg 
3181254a7Smrg /**
4181254a7Smrg This module implements a
5*b1e83836Smrg $(HTTP erdani.org/publications/cuj-04-2002.php.html,discriminated union)
6181254a7Smrg type (a.k.a.
7181254a7Smrg $(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
8181254a7Smrg $(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
9181254a7Smrg Such types are useful
10181254a7Smrg for type-uniform binary interfaces, interfacing with scripting
11181254a7Smrg languages, and comfortable exploratory programming.
12181254a7Smrg 
13181254a7Smrg A $(LREF Variant) object can hold a value of any type, with very few
14181254a7Smrg restrictions (such as `shared` types and noncopyable types). Setting the value
15181254a7Smrg is as immediate as assigning to the `Variant` object. To read back the value of
16*b1e83836Smrg the appropriate type `T`, use the $(LREF get) method. To query whether a
17*b1e83836Smrg `Variant` currently holds a value of type `T`, use $(LREF peek). To fetch the
18181254a7Smrg exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19181254a7Smrg the current value.
20181254a7Smrg 
21181254a7Smrg In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
22181254a7Smrg type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
23181254a7Smrg types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
24181254a7Smrg string)) may only hold an `int` or a `string`).
25181254a7Smrg 
26*b1e83836Smrg $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
27*b1e83836Smrg code. Instead, use $(REF SumType, std,sumtype).)
28*b1e83836Smrg 
29181254a7Smrg Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
30181254a7Smrg prompting the following improvements: (1) better support for arrays; (2) support
31181254a7Smrg for associative arrays; (3) friendlier behavior towards the garbage collector.
32181254a7Smrg Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
33181254a7Smrg License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
34181254a7Smrg Authors:   $(HTTP erdani.org, Andrei Alexandrescu)
35*b1e83836Smrg Source:    $(PHOBOSSRC std/variant.d)
36181254a7Smrg */
37181254a7Smrg module std.variant;
38181254a7Smrg 
39181254a7Smrg import std.meta, std.traits, std.typecons;
40181254a7Smrg 
41181254a7Smrg ///
42181254a7Smrg @system unittest
43181254a7Smrg {
44181254a7Smrg     Variant a; // Must assign before use, otherwise exception ensues
45181254a7Smrg     // Initialize with an integer; make the type int
46181254a7Smrg     Variant b = 42;
47181254a7Smrg     assert(b.type == typeid(int));
48181254a7Smrg     // Peek at the value
49181254a7Smrg     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
50181254a7Smrg     // Automatically convert per language rules
51181254a7Smrg     auto x = b.get!(real);
52181254a7Smrg 
53181254a7Smrg     // Assign any other type, including other variants
54181254a7Smrg     a = b;
55181254a7Smrg     a = 3.14;
56181254a7Smrg     assert(a.type == typeid(double));
57181254a7Smrg     // Implicit conversions work just as with built-in types
58181254a7Smrg     assert(a < b);
59181254a7Smrg     // Check for convertibility
60181254a7Smrg     assert(!a.convertsTo!(int)); // double not convertible to int
61181254a7Smrg     // Strings and all other arrays are supported
62181254a7Smrg     a = "now I'm a string";
63181254a7Smrg     assert(a == "now I'm a string");
64181254a7Smrg 
65181254a7Smrg     // can also assign arrays
66181254a7Smrg     a = new int[42];
67181254a7Smrg     assert(a.length == 42);
68181254a7Smrg     a[5] = 7;
69181254a7Smrg     assert(a[5] == 7);
70181254a7Smrg 
71181254a7Smrg     // Can also assign class values
72181254a7Smrg     class Foo {}
73181254a7Smrg     auto foo = new Foo;
74181254a7Smrg     a = foo;
75181254a7Smrg     assert(*a.peek!(Foo) == foo); // and full type information is preserved
76181254a7Smrg }
77181254a7Smrg 
78181254a7Smrg /++
79*b1e83836Smrg     Gives the `sizeof` the largest type given.
80*b1e83836Smrg 
81*b1e83836Smrg     See_Also: $(LINK https://forum.dlang.org/thread/wbpnncxepehgcswhuazl@forum.dlang.org?page=1)
82181254a7Smrg   +/
maxSize(Ts...)83*b1e83836Smrg template maxSize(Ts...)
84181254a7Smrg {
85*b1e83836Smrg     align(1) union Impl
86181254a7Smrg     {
87*b1e83836Smrg         static foreach (i, T; Ts)
88*b1e83836Smrg         {
89*b1e83836Smrg             static if (!is(T == void))
90*b1e83836Smrg                 mixin("T _field_", i, ";");
91181254a7Smrg         }
92181254a7Smrg     }
93*b1e83836Smrg     enum maxSize = Impl.sizeof;
94181254a7Smrg }
95181254a7Smrg 
96181254a7Smrg ///
97181254a7Smrg @safe unittest
98181254a7Smrg {
99*b1e83836Smrg     struct Cat { int a, b, c; }
100*b1e83836Smrg 
101*b1e83836Smrg     align(1) struct S
102*b1e83836Smrg     {
103*b1e83836Smrg         long l;
104*b1e83836Smrg         ubyte b;
105*b1e83836Smrg     }
106*b1e83836Smrg 
107*b1e83836Smrg     align(1) struct T
108*b1e83836Smrg     {
109*b1e83836Smrg         ubyte b;
110*b1e83836Smrg         long l;
111*b1e83836Smrg     }
112*b1e83836Smrg 
113181254a7Smrg     static assert(maxSize!(int, long) == 8);
114181254a7Smrg     static assert(maxSize!(bool, byte) == 1);
115181254a7Smrg     static assert(maxSize!(bool, Cat) == 12);
116*b1e83836Smrg     static assert(maxSize!(char) == 1);
117*b1e83836Smrg     static assert(maxSize!(char, short, ubyte) == 2);
118*b1e83836Smrg     static assert(maxSize!(char, long, ubyte) == 8);
119*b1e83836Smrg     import std.algorithm.comparison : max;
120*b1e83836Smrg     static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof));
121*b1e83836Smrg     static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof));
122*b1e83836Smrg     static assert(maxSize!(int, ubyte[7]) == 7);
123*b1e83836Smrg     static assert(maxSize!(int, ubyte[3]) == 4);
124*b1e83836Smrg     static assert(maxSize!(int, int, ubyte[3]) == 4);
125*b1e83836Smrg     static assert(maxSize!(void, int, ubyte[3]) == 4);
126*b1e83836Smrg     static assert(maxSize!(void) == 1);
127181254a7Smrg }
128181254a7Smrg 
129181254a7Smrg struct This;
130181254a7Smrg 
131*b1e83836Smrg private alias This2Variant(V, T...) = AliasSeq!(ReplaceTypeUnless!(isAlgebraic, This, V, T));
132*b1e83836Smrg 
133*b1e83836Smrg // We can't just use maxAlignment because no types might be specified
134*b1e83836Smrg // to VariantN, so handle that here and then pass along the rest.
135*b1e83836Smrg private template maxVariantAlignment(U...)
136*b1e83836Smrg if (isTypeTuple!U)
137*b1e83836Smrg {
138*b1e83836Smrg     static if (U.length == 0)
139*b1e83836Smrg     {
140*b1e83836Smrg         import std.algorithm.comparison : max;
141*b1e83836Smrg         enum maxVariantAlignment = max(real.alignof, size_t.alignof);
142*b1e83836Smrg     }
143*b1e83836Smrg     else
144*b1e83836Smrg         enum maxVariantAlignment = maxAlignment!(U);
145*b1e83836Smrg }
146181254a7Smrg 
147181254a7Smrg /**
148181254a7Smrg  * Back-end type seldom used directly by user
149*b1e83836Smrg  * code. Two commonly-used types using `VariantN` are:
150181254a7Smrg  *
151181254a7Smrg  * $(OL $(LI $(LREF Algebraic): A closed discriminated union with a
152181254a7Smrg  * limited type universe (e.g., $(D Algebraic!(int, double,
153181254a7Smrg  * string)) only accepts these three types and rejects anything
154181254a7Smrg  * else).) $(LI $(LREF Variant): An open discriminated union allowing an
155*b1e83836Smrg  * unbounded set of types. If any of the types in the `Variant`
156181254a7Smrg  * are larger than the largest built-in type, they will automatically
157181254a7Smrg  * be boxed. This means that even large types will only be the size
158*b1e83836Smrg  * of a pointer within the `Variant`, but this also implies some
159*b1e83836Smrg  * overhead. `Variant` can accommodate all primitive types and
160181254a7Smrg  * all user-defined types.))
161181254a7Smrg  *
162*b1e83836Smrg  * Both `Algebraic` and `Variant` share $(D
163181254a7Smrg  * VariantN)'s interface. (See their respective documentations below.)
164181254a7Smrg  *
165*b1e83836Smrg  * `VariantN` is a discriminated union type parameterized
166*b1e83836Smrg  * with the largest size of the types stored (`maxDataSize`)
167*b1e83836Smrg  * and with the list of allowed types (`AllowedTypes`). If
168181254a7Smrg  * the list is empty, then any type up of size up to $(D
169181254a7Smrg  * maxDataSize) (rounded up for alignment) can be stored in a
170*b1e83836Smrg  * `VariantN` object without being boxed (types larger
171181254a7Smrg  * than this will be boxed).
172181254a7Smrg  *
173181254a7Smrg  */
VariantN(size_t maxDataSize,AllowedTypesParam...)174181254a7Smrg struct VariantN(size_t maxDataSize, AllowedTypesParam...)
175181254a7Smrg {
176181254a7Smrg     /**
177181254a7Smrg     The list of allowed types. If empty, any type is allowed.
178181254a7Smrg     */
179181254a7Smrg     alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam);
180181254a7Smrg 
181181254a7Smrg private:
182181254a7Smrg     // Compute the largest practical size from maxDataSize
183181254a7Smrg     struct SizeChecker
184181254a7Smrg     {
185181254a7Smrg         int function() fptr;
186181254a7Smrg         ubyte[maxDataSize] data;
187181254a7Smrg     }
188181254a7Smrg     enum size = SizeChecker.sizeof - (int function()).sizeof;
189181254a7Smrg 
190*b1e83836Smrg     /** Tells whether a type `T` is statically _allowed for
191*b1e83836Smrg      * storage inside a `VariantN` object by looking
192*b1e83836Smrg      * `T` up in `AllowedTypes`.
193181254a7Smrg      */
194181254a7Smrg     public template allowed(T)
195181254a7Smrg     {
196181254a7Smrg         enum bool allowed
197181254a7Smrg             = is(T == VariantN)
198181254a7Smrg             ||
199181254a7Smrg             //T.sizeof <= size &&
200181254a7Smrg             (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0);
201181254a7Smrg     }
202181254a7Smrg 
203181254a7Smrg     // Each internal operation is encoded with an identifier. See
204181254a7Smrg     // the "handler" function below.
205181254a7Smrg     enum OpID { getTypeInfo, get, compare, equals, testConversion, toString,
206181254a7Smrg             index, indexAssign, catAssign, copyOut, length,
207181254a7Smrg             apply, postblit, destruct }
208181254a7Smrg 
209181254a7Smrg     // state
210181254a7Smrg     union
211181254a7Smrg     {
212*b1e83836Smrg         align(maxVariantAlignment!(AllowedTypes)) ubyte[size] store;
213181254a7Smrg         // conservatively mark the region as pointers
214181254a7Smrg         static if (size >= (void*).sizeof)
215181254a7Smrg             void*[size / (void*).sizeof] p;
216181254a7Smrg     }
217*b1e83836Smrg     ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
218*b1e83836Smrg         = &handler!(void);
219181254a7Smrg 
220181254a7Smrg     // internals
221181254a7Smrg     // Handler for an uninitialized value
222181254a7Smrg     static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm)
223181254a7Smrg     {
224181254a7Smrg         switch (selector)
225181254a7Smrg         {
226181254a7Smrg         case OpID.getTypeInfo:
227181254a7Smrg             *cast(TypeInfo *) parm = typeid(A);
228181254a7Smrg             break;
229181254a7Smrg         case OpID.copyOut:
230181254a7Smrg             auto target = cast(VariantN *) parm;
231181254a7Smrg             target.fptr = &handler!(A);
232181254a7Smrg             // no need to copy the data (it's garbage)
233181254a7Smrg             break;
234181254a7Smrg         case OpID.compare:
235181254a7Smrg         case OpID.equals:
236181254a7Smrg             auto rhs = cast(const VariantN *) parm;
237181254a7Smrg             return rhs.peek!(A)
238181254a7Smrg                 ? 0 // all uninitialized are equal
239181254a7Smrg                 : ptrdiff_t.min; // uninitialized variant is not comparable otherwise
240181254a7Smrg         case OpID.toString:
241181254a7Smrg             string * target = cast(string*) parm;
242181254a7Smrg             *target = "<Uninitialized VariantN>";
243181254a7Smrg             break;
244181254a7Smrg         case OpID.postblit:
245181254a7Smrg         case OpID.destruct:
246181254a7Smrg             break;
247181254a7Smrg         case OpID.get:
248181254a7Smrg         case OpID.testConversion:
249181254a7Smrg         case OpID.index:
250181254a7Smrg         case OpID.indexAssign:
251181254a7Smrg         case OpID.catAssign:
252181254a7Smrg         case OpID.length:
253181254a7Smrg             throw new VariantException(
254181254a7Smrg                 "Attempt to use an uninitialized VariantN");
255181254a7Smrg         default: assert(false, "Invalid OpID");
256181254a7Smrg         }
257181254a7Smrg         return 0;
258181254a7Smrg     }
259181254a7Smrg 
260181254a7Smrg     // Handler for all of a type's operations
261181254a7Smrg     static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
262181254a7Smrg     {
263181254a7Smrg         import std.conv : to;
264181254a7Smrg         static A* getPtr(void* untyped)
265181254a7Smrg         {
266181254a7Smrg             if (untyped)
267181254a7Smrg             {
268181254a7Smrg                 static if (A.sizeof <= size)
269181254a7Smrg                     return cast(A*) untyped;
270181254a7Smrg                 else
271181254a7Smrg                     return *cast(A**) untyped;
272181254a7Smrg             }
273181254a7Smrg             return null;
274181254a7Smrg         }
275181254a7Smrg 
276181254a7Smrg         static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector)
277181254a7Smrg         {
278181254a7Smrg             static if (is(typeof(*rhsPA == *zis)))
279181254a7Smrg             {
280*b1e83836Smrg                 enum isEmptyStructWithoutOpEquals = is(A == struct) && A.tupleof.length == 0 &&
281*b1e83836Smrg                                                     !__traits(hasMember, A, "opEquals");
282*b1e83836Smrg                 static if (isEmptyStructWithoutOpEquals)
283181254a7Smrg                 {
284*b1e83836Smrg                     // The check above will always succeed if A is an empty struct.
285*b1e83836Smrg                     // Don't generate unreachable code as seen in
286*b1e83836Smrg                     // https://issues.dlang.org/show_bug.cgi?id=21231
287181254a7Smrg                     return 0;
288181254a7Smrg                 }
289*b1e83836Smrg                 else
290*b1e83836Smrg                 {
291*b1e83836Smrg                     if (*rhsPA == *zis)
292*b1e83836Smrg                         return 0;
293181254a7Smrg                     static if (is(typeof(*zis < *rhsPA)))
294181254a7Smrg                     {
295181254a7Smrg                         // Many types (such as any using the default Object opCmp)
296181254a7Smrg                         // will throw on an invalid opCmp, so do it only
297181254a7Smrg                         // if the caller requests it.
298181254a7Smrg                         if (selector == OpID.compare)
299181254a7Smrg                             return *zis < *rhsPA ? -1 : 1;
300181254a7Smrg                         else
301181254a7Smrg                             return ptrdiff_t.min;
302181254a7Smrg                     }
303181254a7Smrg                     else
304181254a7Smrg                     {
305181254a7Smrg                         // Not equal, and type does not support ordering
306181254a7Smrg                         // comparisons.
307181254a7Smrg                         return ptrdiff_t.min;
308181254a7Smrg                     }
309181254a7Smrg                 }
310*b1e83836Smrg             }
311181254a7Smrg             else
312181254a7Smrg             {
313181254a7Smrg                 // Type does not support comparisons at all.
314181254a7Smrg                 return ptrdiff_t.min;
315181254a7Smrg             }
316181254a7Smrg         }
317181254a7Smrg 
318181254a7Smrg         auto zis = getPtr(pStore);
319181254a7Smrg         // Input: TypeInfo object
320181254a7Smrg         // Output: target points to a copy of *me, if me was not null
321181254a7Smrg         // Returns: true iff the A can be converted to the type represented
322181254a7Smrg         // by the incoming TypeInfo
323181254a7Smrg         static bool tryPutting(A* src, TypeInfo targetType, void* target)
324181254a7Smrg         {
325181254a7Smrg             alias UA = Unqual!A;
326*b1e83836Smrg             static if (isStaticArray!A && is(typeof(UA.init[0])))
327*b1e83836Smrg             {
328*b1e83836Smrg                 alias MutaTypes = AliasSeq!(UA, typeof(UA.init[0])[], AllImplicitConversionTargets!UA);
329*b1e83836Smrg             }
330*b1e83836Smrg             else
331*b1e83836Smrg             {
332*b1e83836Smrg                 alias MutaTypes = AliasSeq!(UA, AllImplicitConversionTargets!UA);
333*b1e83836Smrg             }
334181254a7Smrg             alias ConstTypes = staticMap!(ConstOf, MutaTypes);
335181254a7Smrg             alias SharedTypes = staticMap!(SharedOf, MutaTypes);
336181254a7Smrg             alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes);
337181254a7Smrg             alias ImmuTypes  = staticMap!(ImmutableOf, MutaTypes);
338181254a7Smrg 
339181254a7Smrg             static if (is(A == immutable))
340181254a7Smrg                 alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes);
341181254a7Smrg             else static if (is(A == shared))
342181254a7Smrg             {
343181254a7Smrg                 static if (is(A == const))
344181254a7Smrg                     alias AllTypes = SharedConstTypes;
345181254a7Smrg                 else
346181254a7Smrg                     alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes);
347181254a7Smrg             }
348181254a7Smrg             else
349181254a7Smrg             {
350181254a7Smrg                 static if (is(A == const))
351181254a7Smrg                     alias AllTypes = ConstTypes;
352181254a7Smrg                 else
353181254a7Smrg                     alias AllTypes = AliasSeq!(MutaTypes, ConstTypes);
354181254a7Smrg             }
355181254a7Smrg 
356181254a7Smrg             foreach (T ; AllTypes)
357181254a7Smrg             {
358181254a7Smrg                 if (targetType != typeid(T))
359181254a7Smrg                     continue;
360181254a7Smrg 
361*b1e83836Smrg                 // SPECIAL NOTE: variant only will ever create a new value with
362*b1e83836Smrg                 // tryPutting (effectively), and T is ALWAYS the same type of
363*b1e83836Smrg                 // A, but with different modifiers (and a limited set of
364*b1e83836Smrg                 // implicit targets). So this checks to see if we can construct
365*b1e83836Smrg                 // a T from A, knowing that prerequisite. This handles issues
366*b1e83836Smrg                 // where the type contains some constant data aside from the
367*b1e83836Smrg                 // modifiers on the type itself.
368*b1e83836Smrg                 static if (is(typeof(delegate T() {return *src;})) ||
369181254a7Smrg                            is(T ==        const(U), U) ||
370181254a7Smrg                            is(T ==       shared(U), U) ||
371181254a7Smrg                            is(T == shared const(U), U) ||
372181254a7Smrg                            is(T ==    immutable(U), U))
373181254a7Smrg                 {
374*b1e83836Smrg                     import core.internal.lifetime : emplaceRef;
375181254a7Smrg 
376181254a7Smrg                     auto zat = cast(T*) target;
377181254a7Smrg                     if (src)
378181254a7Smrg                     {
379181254a7Smrg                         static if (T.sizeof > 0)
380181254a7Smrg                             assert(target, "target must be non-null");
381181254a7Smrg 
382*b1e83836Smrg                         static if (isStaticArray!A && isDynamicArray!T)
383*b1e83836Smrg                         {
384*b1e83836Smrg                             auto this_ = (*src)[];
385*b1e83836Smrg                             emplaceRef(*cast(Unqual!T*) zat, cast(Unqual!T) this_);
386*b1e83836Smrg                         }
387*b1e83836Smrg                         else
388*b1e83836Smrg                         {
389181254a7Smrg                             emplaceRef(*cast(Unqual!T*) zat, *cast(UA*) src);
390181254a7Smrg                         }
391181254a7Smrg                     }
392*b1e83836Smrg                 }
393181254a7Smrg                 else
394181254a7Smrg                 {
395181254a7Smrg                     // type T is not constructible from A
396181254a7Smrg                     if (src)
397181254a7Smrg                         assert(false, A.stringof);
398181254a7Smrg                 }
399181254a7Smrg                 return true;
400181254a7Smrg             }
401181254a7Smrg             return false;
402181254a7Smrg         }
403181254a7Smrg 
404181254a7Smrg         switch (selector)
405181254a7Smrg         {
406181254a7Smrg         case OpID.getTypeInfo:
407181254a7Smrg             *cast(TypeInfo *) parm = typeid(A);
408181254a7Smrg             break;
409181254a7Smrg         case OpID.copyOut:
410181254a7Smrg             auto target = cast(VariantN *) parm;
411181254a7Smrg             assert(target);
412181254a7Smrg 
413181254a7Smrg             static if (target.size < A.sizeof)
414181254a7Smrg             {
415181254a7Smrg                 if (target.type.tsize < A.sizeof)
416*b1e83836Smrg                 {
417*b1e83836Smrg                     static if (is(A == U[n], U, size_t n))
418*b1e83836Smrg                     {
419*b1e83836Smrg                         A* p = cast(A*)(new U[n]).ptr;
420*b1e83836Smrg                     }
421*b1e83836Smrg                     else
422*b1e83836Smrg                     {
423*b1e83836Smrg                         A* p = new A;
424*b1e83836Smrg                     }
425*b1e83836Smrg                     *cast(A**)&target.store = p;
426*b1e83836Smrg                 }
427181254a7Smrg             }
428181254a7Smrg             tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store))
429181254a7Smrg                 || assert(false);
430181254a7Smrg             target.fptr = &handler!(A);
431181254a7Smrg             break;
432181254a7Smrg         case OpID.get:
433181254a7Smrg             auto t = * cast(Tuple!(TypeInfo, void*)*) parm;
434181254a7Smrg             return !tryPutting(zis, t[0], t[1]);
435181254a7Smrg         case OpID.testConversion:
436181254a7Smrg             return !tryPutting(null, *cast(TypeInfo*) parm, null);
437181254a7Smrg         case OpID.compare:
438181254a7Smrg         case OpID.equals:
439181254a7Smrg             auto rhsP = cast(VariantN *) parm;
440181254a7Smrg             auto rhsType = rhsP.type;
441181254a7Smrg             // Are we the same?
442181254a7Smrg             if (rhsType == typeid(A))
443181254a7Smrg             {
444181254a7Smrg                 // cool! Same type!
445181254a7Smrg                 auto rhsPA = getPtr(&rhsP.store);
446181254a7Smrg                 return compare(rhsPA, zis, selector);
447181254a7Smrg             }
448181254a7Smrg             else if (rhsType == typeid(void))
449181254a7Smrg             {
450181254a7Smrg                 // No support for ordering comparisons with
451181254a7Smrg                 // uninitialized vars
452181254a7Smrg                 return ptrdiff_t.min;
453181254a7Smrg             }
454181254a7Smrg             VariantN temp;
455181254a7Smrg             // Do I convert to rhs?
456181254a7Smrg             if (tryPutting(zis, rhsType, &temp.store))
457181254a7Smrg             {
458181254a7Smrg                 // cool, I do; temp's store contains my data in rhs's type!
459181254a7Smrg                 // also fix up its fptr
460181254a7Smrg                 temp.fptr = rhsP.fptr;
461181254a7Smrg                 // now lhsWithRhsType is a full-blown VariantN of rhs's type
462181254a7Smrg                 if (selector == OpID.compare)
463181254a7Smrg                     return temp.opCmp(*rhsP);
464181254a7Smrg                 else
465181254a7Smrg                     return temp.opEquals(*rhsP) ? 0 : 1;
466181254a7Smrg             }
467181254a7Smrg             // Does rhs convert to zis?
468181254a7Smrg             auto t = tuple(typeid(A), &temp.store);
469181254a7Smrg             if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0)
470181254a7Smrg             {
471181254a7Smrg                 // cool! Now temp has rhs in my type!
472181254a7Smrg                 auto rhsPA = getPtr(&temp.store);
473181254a7Smrg                 return compare(rhsPA, zis, selector);
474181254a7Smrg             }
475*b1e83836Smrg             // Generate the function below only if the Variant's type is
476*b1e83836Smrg             // comparable with 'null'
477*b1e83836Smrg             static if (__traits(compiles, () => A.init == null))
478*b1e83836Smrg             {
479*b1e83836Smrg                 if (rhsType == typeid(null))
480*b1e83836Smrg                 {
481*b1e83836Smrg                     // if rhsType is typeof(null), then we're comparing with 'null'
482*b1e83836Smrg                     // this takes into account 'opEquals' and 'opCmp'
483*b1e83836Smrg                     // all types that can compare with null have to following properties:
484*b1e83836Smrg                     // if it's 'null' then it's equal to null, otherwise it's always greater
485*b1e83836Smrg                     // than 'null'
486*b1e83836Smrg                     return *zis == null ? 0 : 1;
487*b1e83836Smrg                 }
488*b1e83836Smrg             }
489181254a7Smrg             return ptrdiff_t.min; // dunno
490181254a7Smrg         case OpID.toString:
491181254a7Smrg             auto target = cast(string*) parm;
492181254a7Smrg             static if (is(typeof(to!(string)(*zis))))
493181254a7Smrg             {
494181254a7Smrg                 *target = to!(string)(*zis);
495181254a7Smrg                 break;
496181254a7Smrg             }
497181254a7Smrg             // TODO: The following test evaluates to true for shared objects.
498181254a7Smrg             //       Use __traits for now until this is sorted out.
499181254a7Smrg             // else static if (is(typeof((*zis).toString)))
500181254a7Smrg             else static if (__traits(compiles, {(*zis).toString();}))
501181254a7Smrg             {
502181254a7Smrg                 *target = (*zis).toString();
503181254a7Smrg                 break;
504181254a7Smrg             }
505181254a7Smrg             else
506181254a7Smrg             {
507181254a7Smrg                 throw new VariantException(typeid(A), typeid(string));
508181254a7Smrg             }
509181254a7Smrg 
510181254a7Smrg         case OpID.index:
511181254a7Smrg             auto result = cast(Variant*) parm;
512*b1e83836Smrg             static if (isArray!(A) && !is(immutable typeof(A.init[0]) == immutable void))
513181254a7Smrg             {
514181254a7Smrg                 // array type; input and output are the same VariantN
515181254a7Smrg                 size_t index = result.convertsTo!(int)
516181254a7Smrg                     ? result.get!(int) : result.get!(size_t);
517181254a7Smrg                 *result = (*zis)[index];
518181254a7Smrg                 break;
519181254a7Smrg             }
520181254a7Smrg             else static if (isAssociativeArray!(A))
521181254a7Smrg             {
522181254a7Smrg                 *result = (*zis)[result.get!(typeof(A.init.keys[0]))];
523181254a7Smrg                 break;
524181254a7Smrg             }
525181254a7Smrg             else
526181254a7Smrg             {
527181254a7Smrg                 throw new VariantException(typeid(A), result[0].type);
528181254a7Smrg             }
529181254a7Smrg 
530181254a7Smrg         case OpID.indexAssign:
531181254a7Smrg             // array type; result comes first, index comes second
532181254a7Smrg             auto args = cast(Variant*) parm;
533181254a7Smrg             static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0])))
534181254a7Smrg             {
535181254a7Smrg                 size_t index = args[1].convertsTo!(int)
536181254a7Smrg                     ? args[1].get!(int) : args[1].get!(size_t);
537181254a7Smrg                 (*zis)[index] = args[0].get!(typeof((*zis)[0]));
538181254a7Smrg                 break;
539181254a7Smrg             }
540*b1e83836Smrg             else static if (isAssociativeArray!(A) && is(typeof((*zis)[A.init.keys[0]] = A.init.values[0])))
541181254a7Smrg             {
542181254a7Smrg                 (*zis)[args[1].get!(typeof(A.init.keys[0]))]
543181254a7Smrg                     = args[0].get!(typeof(A.init.values[0]));
544181254a7Smrg                 break;
545181254a7Smrg             }
546181254a7Smrg             else
547181254a7Smrg             {
548181254a7Smrg                 throw new VariantException(typeid(A), args[0].type);
549181254a7Smrg             }
550181254a7Smrg 
551181254a7Smrg         case OpID.catAssign:
552*b1e83836Smrg             static if (!is(immutable typeof((*zis)[0]) == immutable void) &&
553*b1e83836Smrg                     is(typeof((*zis)[0])) && is(typeof(*zis ~= *zis)))
554181254a7Smrg             {
555181254a7Smrg                 // array type; parm is the element to append
556181254a7Smrg                 auto arg = cast(Variant*) parm;
557181254a7Smrg                 alias E = typeof((*zis)[0]);
558181254a7Smrg                 if (arg[0].convertsTo!(E))
559181254a7Smrg                 {
560181254a7Smrg                     // append one element to the array
561181254a7Smrg                     (*zis) ~= [ arg[0].get!(E) ];
562181254a7Smrg                 }
563181254a7Smrg                 else
564181254a7Smrg                 {
565181254a7Smrg                     // append a whole array to the array
566181254a7Smrg                     (*zis) ~= arg[0].get!(A);
567181254a7Smrg                 }
568181254a7Smrg                 break;
569181254a7Smrg             }
570181254a7Smrg             else
571181254a7Smrg             {
572181254a7Smrg                 throw new VariantException(typeid(A), typeid(void[]));
573181254a7Smrg             }
574181254a7Smrg 
575181254a7Smrg         case OpID.length:
576181254a7Smrg             static if (isArray!(A) || isAssociativeArray!(A))
577181254a7Smrg             {
578181254a7Smrg                 return zis.length;
579181254a7Smrg             }
580181254a7Smrg             else
581181254a7Smrg             {
582181254a7Smrg                 throw new VariantException(typeid(A), typeid(void[]));
583181254a7Smrg             }
584181254a7Smrg 
585181254a7Smrg         case OpID.apply:
586181254a7Smrg             static if (!isFunctionPointer!A && !isDelegate!A)
587181254a7Smrg             {
588181254a7Smrg                 import std.conv : text;
589181254a7Smrg                 import std.exception : enforce;
590181254a7Smrg                 enforce(0, text("Cannot apply `()' to a value of type `",
591181254a7Smrg                                 A.stringof, "'."));
592181254a7Smrg             }
593181254a7Smrg             else
594181254a7Smrg             {
595181254a7Smrg                 import std.conv : text;
596181254a7Smrg                 import std.exception : enforce;
597181254a7Smrg                 alias ParamTypes = Parameters!A;
598181254a7Smrg                 auto p = cast(Variant*) parm;
599181254a7Smrg                 auto argCount = p.get!size_t;
600181254a7Smrg                 // To assign the tuple we need to use the unqualified version,
601181254a7Smrg                 // otherwise we run into issues such as with const values.
602181254a7Smrg                 // We still get the actual type from the Variant though
603181254a7Smrg                 // to ensure that we retain const correctness.
604181254a7Smrg                 Tuple!(staticMap!(Unqual, ParamTypes)) t;
605181254a7Smrg                 enforce(t.length == argCount,
606181254a7Smrg                         text("Argument count mismatch: ",
607181254a7Smrg                              A.stringof, " expects ", t.length,
608181254a7Smrg                              " argument(s), not ", argCount, "."));
609181254a7Smrg                 auto variantArgs = p[1 .. argCount + 1];
610181254a7Smrg                 foreach (i, T; ParamTypes)
611181254a7Smrg                 {
612181254a7Smrg                     t[i] = cast() variantArgs[i].get!T;
613181254a7Smrg                 }
614181254a7Smrg 
615181254a7Smrg                 auto args = cast(Tuple!(ParamTypes))t;
616181254a7Smrg                 static if (is(ReturnType!A == void))
617181254a7Smrg                 {
618181254a7Smrg                     (*zis)(args.expand);
619181254a7Smrg                     *p = Variant.init; // void returns uninitialized Variant.
620181254a7Smrg                 }
621181254a7Smrg                 else
622181254a7Smrg                 {
623181254a7Smrg                     *p = (*zis)(args.expand);
624181254a7Smrg                 }
625181254a7Smrg             }
626181254a7Smrg             break;
627181254a7Smrg 
628181254a7Smrg         case OpID.postblit:
629181254a7Smrg             static if (hasElaborateCopyConstructor!A)
630181254a7Smrg             {
631*b1e83836Smrg                 zis.__xpostblit();
632181254a7Smrg             }
633181254a7Smrg             break;
634181254a7Smrg 
635181254a7Smrg         case OpID.destruct:
636181254a7Smrg             static if (hasElaborateDestructor!A)
637181254a7Smrg             {
638*b1e83836Smrg                 zis.__xdtor();
639181254a7Smrg             }
640181254a7Smrg             break;
641181254a7Smrg 
642181254a7Smrg         default: assert(false);
643181254a7Smrg         }
644181254a7Smrg         return 0;
645181254a7Smrg     }
646181254a7Smrg 
647181254a7Smrg public:
648*b1e83836Smrg     /** Constructs a `VariantN` value given an argument of a
649181254a7Smrg      * generic type. Statically rejects disallowed types.
650181254a7Smrg      */
651181254a7Smrg 
652181254a7Smrg     this(T)(T value)
653181254a7Smrg     {
654181254a7Smrg         static assert(allowed!(T), "Cannot store a " ~ T.stringof
655181254a7Smrg             ~ " in a " ~ VariantN.stringof);
656181254a7Smrg         opAssign(value);
657181254a7Smrg     }
658181254a7Smrg 
659181254a7Smrg     /// Allows assignment from a subset algebraic type
660181254a7Smrg     this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
661181254a7Smrg         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
662181254a7Smrg     {
663181254a7Smrg         opAssign(value);
664181254a7Smrg     }
665181254a7Smrg 
666181254a7Smrg     static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
667181254a7Smrg     {
668181254a7Smrg         this(this)
669181254a7Smrg         {
670181254a7Smrg             fptr(OpID.postblit, &store, null);
671181254a7Smrg         }
672181254a7Smrg     }
673181254a7Smrg 
674181254a7Smrg     static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
675181254a7Smrg     {
676181254a7Smrg         ~this()
677181254a7Smrg         {
678*b1e83836Smrg             // Infer the safety of the provided types
679*b1e83836Smrg             static if (AllowedTypes.length)
680*b1e83836Smrg             {
681*b1e83836Smrg                 if (0)
682*b1e83836Smrg                 {
683*b1e83836Smrg                     AllowedTypes var;
684*b1e83836Smrg                 }
685*b1e83836Smrg             }
686*b1e83836Smrg             (() @trusted => fptr(OpID.destruct, &store, null))();
687181254a7Smrg         }
688181254a7Smrg     }
689181254a7Smrg 
690*b1e83836Smrg     /** Assigns a `VariantN` from a generic
691181254a7Smrg      * argument. Statically rejects disallowed types. */
692181254a7Smrg 
693181254a7Smrg     VariantN opAssign(T)(T rhs)
694181254a7Smrg     {
695181254a7Smrg         static assert(allowed!(T), "Cannot store a " ~ T.stringof
696181254a7Smrg             ~ " in a " ~ VariantN.stringof ~ ". Valid types are "
697181254a7Smrg                 ~ AllowedTypes.stringof);
698181254a7Smrg 
699181254a7Smrg         static if (is(T : VariantN))
700181254a7Smrg         {
701181254a7Smrg             rhs.fptr(OpID.copyOut, &rhs.store, &this);
702181254a7Smrg         }
703181254a7Smrg         else static if (is(T : const(VariantN)))
704181254a7Smrg         {
705181254a7Smrg             static assert(false,
706181254a7Smrg                     "Assigning Variant objects from const Variant"~
707181254a7Smrg                     " objects is currently not supported.");
708181254a7Smrg         }
709181254a7Smrg         else
710181254a7Smrg         {
711*b1e83836Smrg             import core.lifetime : copyEmplace;
712*b1e83836Smrg 
713181254a7Smrg             static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
714181254a7Smrg             {
715181254a7Smrg                 // Assignment should destruct previous value
716181254a7Smrg                 fptr(OpID.destruct, &store, null);
717181254a7Smrg             }
718181254a7Smrg 
719181254a7Smrg             static if (T.sizeof <= size)
720*b1e83836Smrg                 copyEmplace(rhs, *cast(T*) &store);
721181254a7Smrg             else
722181254a7Smrg             {
723*b1e83836Smrg                 static if (is(T == U[n], U, size_t n))
724*b1e83836Smrg                     auto p = cast(T*) (new U[n]).ptr;
725181254a7Smrg                 else
726181254a7Smrg                     auto p = new T;
727*b1e83836Smrg                 copyEmplace(rhs, *p);
728*b1e83836Smrg                 *(cast(T**) &store) = p;
729181254a7Smrg             }
730*b1e83836Smrg 
731181254a7Smrg             fptr = &handler!(T);
732181254a7Smrg         }
733181254a7Smrg         return this;
734181254a7Smrg     }
735181254a7Smrg 
736181254a7Smrg     // Allow assignment from another variant which is a subset of this one
737181254a7Smrg     VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
738181254a7Smrg         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
739181254a7Smrg     {
740181254a7Smrg         // discover which type rhs is actually storing
741181254a7Smrg         foreach (V; T.AllowedTypes)
742181254a7Smrg             if (rhs.type == typeid(V))
743181254a7Smrg                 return this = rhs.get!V;
744181254a7Smrg         assert(0, T.AllowedTypes.stringof);
745181254a7Smrg     }
746181254a7Smrg 
747181254a7Smrg 
748181254a7Smrg     Variant opCall(P...)(auto ref P params)
749181254a7Smrg     {
750181254a7Smrg         Variant[P.length + 1] pack;
751181254a7Smrg         pack[0] = P.length;
752181254a7Smrg         foreach (i, _; params)
753181254a7Smrg         {
754181254a7Smrg             pack[i + 1] = params[i];
755181254a7Smrg         }
756181254a7Smrg         fptr(OpID.apply, &store, &pack);
757181254a7Smrg         return pack[0];
758181254a7Smrg     }
759181254a7Smrg 
760*b1e83836Smrg     /** Returns true if and only if the `VariantN` object
761181254a7Smrg      * holds a valid value (has been initialized with, or assigned
762181254a7Smrg      * from, a valid value).
763181254a7Smrg      */
764181254a7Smrg     @property bool hasValue() const pure nothrow
765181254a7Smrg     {
766181254a7Smrg         // @@@BUG@@@ in compiler, the cast shouldn't be needed
767181254a7Smrg         return cast(typeof(&handler!(void))) fptr != &handler!(void);
768181254a7Smrg     }
769181254a7Smrg 
770181254a7Smrg     ///
771*b1e83836Smrg     version (StdDdoc)
772181254a7Smrg     @system unittest
773181254a7Smrg     {
774181254a7Smrg         Variant a;
775181254a7Smrg         assert(!a.hasValue);
776181254a7Smrg         Variant b;
777181254a7Smrg         a = b;
778181254a7Smrg         assert(!a.hasValue); // still no value
779181254a7Smrg         a = 5;
780181254a7Smrg         assert(a.hasValue);
781181254a7Smrg     }
782181254a7Smrg 
783181254a7Smrg     /**
784*b1e83836Smrg      * If the `VariantN` object holds a value of the
785*b1e83836Smrg      * $(I exact) type `T`, returns a pointer to that
786*b1e83836Smrg      * value. Otherwise, returns `null`. In cases
787*b1e83836Smrg      * where `T` is statically disallowed, $(D
788181254a7Smrg      * peek) will not compile.
789181254a7Smrg      */
790181254a7Smrg     @property inout(T)* peek(T)() inout
791181254a7Smrg     {
792181254a7Smrg         static if (!is(T == void))
793181254a7Smrg             static assert(allowed!(T), "Cannot store a " ~ T.stringof
794181254a7Smrg                     ~ " in a " ~ VariantN.stringof);
795181254a7Smrg         if (type != typeid(T))
796181254a7Smrg             return null;
797181254a7Smrg         static if (T.sizeof <= size)
798181254a7Smrg             return cast(inout T*)&store;
799181254a7Smrg         else
800181254a7Smrg             return *cast(inout T**)&store;
801181254a7Smrg     }
802181254a7Smrg 
803181254a7Smrg     ///
804*b1e83836Smrg     version (StdDdoc)
805181254a7Smrg     @system unittest
806181254a7Smrg     {
807181254a7Smrg         Variant a = 5;
808181254a7Smrg         auto b = a.peek!(int);
809181254a7Smrg         assert(b !is null);
810181254a7Smrg         *b = 6;
811181254a7Smrg         assert(a == 6);
812181254a7Smrg     }
813181254a7Smrg 
814181254a7Smrg     /**
815*b1e83836Smrg      * Returns the `typeid` of the currently held value.
816181254a7Smrg      */
817181254a7Smrg 
818181254a7Smrg     @property TypeInfo type() const nothrow @trusted
819181254a7Smrg     {
820181254a7Smrg         scope(failure) assert(0);
821181254a7Smrg 
822181254a7Smrg         TypeInfo result;
823181254a7Smrg         fptr(OpID.getTypeInfo, null, &result);
824181254a7Smrg         return result;
825181254a7Smrg     }
826181254a7Smrg 
827181254a7Smrg     /**
828*b1e83836Smrg      * Returns `true` if and only if the `VariantN`
829181254a7Smrg      * object holds an object implicitly convertible to type `T`.
830181254a7Smrg      * Implicit convertibility is defined as per
831*b1e83836Smrg      * $(REF_ALTTEXT AllImplicitConversionTargets, AllImplicitConversionTargets, std,traits).
832181254a7Smrg      */
833181254a7Smrg 
834181254a7Smrg     @property bool convertsTo(T)() const
835181254a7Smrg     {
836181254a7Smrg         TypeInfo info = typeid(T);
837181254a7Smrg         return fptr(OpID.testConversion, null, &info) == 0;
838181254a7Smrg     }
839181254a7Smrg 
840181254a7Smrg     /**
841181254a7Smrg     Returns the value stored in the `VariantN` object, either by specifying the
842181254a7Smrg     needed type or the index in the list of allowed types. The latter overload
843181254a7Smrg     only applies to bounded variants (e.g. $(LREF Algebraic)).
844181254a7Smrg 
845181254a7Smrg     Params:
846181254a7Smrg     T = The requested type. The currently stored value must implicitly convert
847181254a7Smrg     to the requested type, in fact `DecayStaticToDynamicArray!T`. If an
848181254a7Smrg     implicit conversion is not possible, throws a `VariantException`.
849181254a7Smrg     index = The index of the type among `AllowedTypesParam`, zero-based.
850181254a7Smrg      */
851181254a7Smrg     @property inout(T) get(T)() inout
852181254a7Smrg     {
853181254a7Smrg         inout(T) result = void;
854181254a7Smrg         static if (is(T == shared))
855181254a7Smrg             alias R = shared Unqual!T;
856181254a7Smrg         else
857181254a7Smrg             alias R = Unqual!T;
858181254a7Smrg         auto buf = tuple(typeid(T), cast(R*)&result);
859181254a7Smrg 
860181254a7Smrg         if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
861181254a7Smrg         {
862181254a7Smrg             throw new VariantException(type, typeid(T));
863181254a7Smrg         }
864181254a7Smrg         return result;
865181254a7Smrg     }
866181254a7Smrg 
867181254a7Smrg     /// Ditto
868181254a7Smrg     @property auto get(uint index)() inout
869181254a7Smrg     if (index < AllowedTypes.length)
870181254a7Smrg     {
871181254a7Smrg         foreach (i, T; AllowedTypes)
872181254a7Smrg         {
873181254a7Smrg             static if (index == i) return get!T;
874181254a7Smrg         }
875181254a7Smrg         assert(0);
876181254a7Smrg     }
877181254a7Smrg 
878181254a7Smrg     /**
879*b1e83836Smrg      * Returns the value stored in the `VariantN` object,
880181254a7Smrg      * explicitly converted (coerced) to the requested type $(D
881*b1e83836Smrg      * T). If `T` is a string type, the value is formatted as
882*b1e83836Smrg      * a string. If the `VariantN` object is a string, a
883*b1e83836Smrg      * parse of the string to type `T` is attempted. If a
884181254a7Smrg      * conversion is not possible, throws a $(D
885181254a7Smrg      * VariantException).
886181254a7Smrg      */
887181254a7Smrg 
888181254a7Smrg     @property T coerce(T)()
889181254a7Smrg     {
890181254a7Smrg         import std.conv : to, text;
891181254a7Smrg         static if (isNumeric!T || isBoolean!T)
892181254a7Smrg         {
893181254a7Smrg             if (convertsTo!real)
894181254a7Smrg             {
895181254a7Smrg                 // maybe optimize this fella; handle ints separately
896181254a7Smrg                 return to!T(get!real);
897181254a7Smrg             }
898181254a7Smrg             else if (convertsTo!(const(char)[]))
899181254a7Smrg             {
900181254a7Smrg                 return to!T(get!(const(char)[]));
901181254a7Smrg             }
902181254a7Smrg             // I'm not sure why this doesn't convert to const(char),
903181254a7Smrg             // but apparently it doesn't (probably a deeper bug).
904181254a7Smrg             //
905181254a7Smrg             // Until that is fixed, this quick addition keeps a common
906181254a7Smrg             // function working. "10".coerce!int ought to work.
907181254a7Smrg             else if (convertsTo!(immutable(char)[]))
908181254a7Smrg             {
909181254a7Smrg                 return to!T(get!(immutable(char)[]));
910181254a7Smrg             }
911181254a7Smrg             else
912181254a7Smrg             {
913181254a7Smrg                 import std.exception : enforce;
914181254a7Smrg                 enforce(false, text("Type ", type, " does not convert to ",
915181254a7Smrg                                 typeid(T)));
916181254a7Smrg                 assert(0);
917181254a7Smrg             }
918181254a7Smrg         }
919181254a7Smrg         else static if (is(T : Object))
920181254a7Smrg         {
921181254a7Smrg             return to!(T)(get!(Object));
922181254a7Smrg         }
923181254a7Smrg         else static if (isSomeString!(T))
924181254a7Smrg         {
925181254a7Smrg             return to!(T)(toString());
926181254a7Smrg         }
927181254a7Smrg         else
928181254a7Smrg         {
929181254a7Smrg             // Fix for bug 1649
930181254a7Smrg             static assert(false, "unsupported type for coercion");
931181254a7Smrg         }
932181254a7Smrg     }
933181254a7Smrg 
934181254a7Smrg     /**
935181254a7Smrg      * Formats the stored value as a string.
936181254a7Smrg      */
937181254a7Smrg 
938181254a7Smrg     string toString()
939181254a7Smrg     {
940181254a7Smrg         string result;
941181254a7Smrg         fptr(OpID.toString, &store, &result) == 0 || assert(false);
942181254a7Smrg         return result;
943181254a7Smrg     }
944181254a7Smrg 
945181254a7Smrg     /**
946181254a7Smrg      * Comparison for equality used by the "==" and "!="  operators.
947181254a7Smrg      */
948181254a7Smrg 
949181254a7Smrg     // returns 1 if the two are equal
950181254a7Smrg     bool opEquals(T)(auto ref T rhs) const
951*b1e83836Smrg     if (allowed!T || is(immutable T == immutable VariantN))
952181254a7Smrg     {
953*b1e83836Smrg         static if (is(immutable T == immutable VariantN))
954181254a7Smrg             alias temp = rhs;
955181254a7Smrg         else
956181254a7Smrg             auto temp = VariantN(rhs);
957181254a7Smrg         return !fptr(OpID.equals, cast(ubyte[size]*) &store,
958181254a7Smrg                      cast(void*) &temp);
959181254a7Smrg     }
960181254a7Smrg 
961181254a7Smrg     // workaround for bug 10567 fix
962181254a7Smrg     int opCmp(ref const VariantN rhs) const
963181254a7Smrg     {
964181254a7Smrg         return (cast() this).opCmp!(VariantN)(cast() rhs);
965181254a7Smrg     }
966181254a7Smrg 
967181254a7Smrg     /**
968181254a7Smrg      * Ordering comparison used by the "<", "<=", ">", and ">="
969181254a7Smrg      * operators. In case comparison is not sensible between the held
970*b1e83836Smrg      * value and `rhs`, an exception is thrown.
971181254a7Smrg      */
972181254a7Smrg 
973181254a7Smrg     int opCmp(T)(T rhs)
974181254a7Smrg     if (allowed!T)  // includes T == VariantN
975181254a7Smrg     {
976181254a7Smrg         static if (is(T == VariantN))
977181254a7Smrg             alias temp = rhs;
978181254a7Smrg         else
979181254a7Smrg             auto temp = VariantN(rhs);
980181254a7Smrg         auto result = fptr(OpID.compare, &store, &temp);
981181254a7Smrg         if (result == ptrdiff_t.min)
982181254a7Smrg         {
983181254a7Smrg             throw new VariantException(type, temp.type);
984181254a7Smrg         }
985181254a7Smrg 
986181254a7Smrg         assert(result >= -1 && result <= 1);  // Should be true for opCmp.
987181254a7Smrg         return cast(int) result;
988181254a7Smrg     }
989181254a7Smrg 
990181254a7Smrg     /**
991181254a7Smrg      * Computes the hash of the held value.
992181254a7Smrg      */
993181254a7Smrg 
994181254a7Smrg     size_t toHash() const nothrow @safe
995181254a7Smrg     {
996181254a7Smrg         return type.getHash(&store);
997181254a7Smrg     }
998181254a7Smrg 
999181254a7Smrg     private VariantN opArithmetic(T, string op)(T other)
1000181254a7Smrg     {
1001181254a7Smrg         static if (isInstanceOf!(.VariantN, T))
1002181254a7Smrg         {
1003181254a7Smrg             string tryUseType(string tp)
1004181254a7Smrg             {
1005181254a7Smrg                 import std.format : format;
1006181254a7Smrg                 return q{
1007181254a7Smrg                     static if (allowed!%1$s && T.allowed!%1$s)
1008181254a7Smrg                         if (convertsTo!%1$s && other.convertsTo!%1$s)
1009181254a7Smrg                             return VariantN(get!%1$s %2$s other.get!%1$s);
1010181254a7Smrg                 }.format(tp, op);
1011181254a7Smrg             }
1012181254a7Smrg 
1013181254a7Smrg             mixin(tryUseType("uint"));
1014181254a7Smrg             mixin(tryUseType("int"));
1015181254a7Smrg             mixin(tryUseType("ulong"));
1016181254a7Smrg             mixin(tryUseType("long"));
1017181254a7Smrg             mixin(tryUseType("float"));
1018181254a7Smrg             mixin(tryUseType("double"));
1019181254a7Smrg             mixin(tryUseType("real"));
1020181254a7Smrg         }
1021181254a7Smrg         else
1022181254a7Smrg         {
1023181254a7Smrg             static if (allowed!T)
1024181254a7Smrg                 if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other"));
1025181254a7Smrg             static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T)
1026181254a7Smrg                 if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other"));
1027181254a7Smrg             static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T)
1028181254a7Smrg                 if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other"));
1029181254a7Smrg             static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T)
1030181254a7Smrg                 if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other"));
1031181254a7Smrg             static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T)
1032181254a7Smrg                 if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other"));
1033181254a7Smrg             static if (allowed!float && is(T : float))
1034181254a7Smrg                 if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other"));
1035181254a7Smrg             static if (allowed!double && is(T : double))
1036181254a7Smrg                 if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other"));
1037181254a7Smrg             static if (allowed!real && is (T : real))
1038181254a7Smrg                 if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other"));
1039181254a7Smrg         }
1040181254a7Smrg 
1041181254a7Smrg         throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof);
1042181254a7Smrg     }
1043181254a7Smrg 
1044181254a7Smrg     private VariantN opLogic(T, string op)(T other)
1045181254a7Smrg     {
1046181254a7Smrg         VariantN result;
1047181254a7Smrg         static if (is(T == VariantN))
1048181254a7Smrg         {
1049181254a7Smrg             if (convertsTo!(uint) && other.convertsTo!(uint))
1050181254a7Smrg                 result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
1051181254a7Smrg             else if (convertsTo!(int) && other.convertsTo!(int))
1052181254a7Smrg                 result = mixin("get!(int) " ~ op ~ " other.get!(int)");
1053181254a7Smrg             else if (convertsTo!(ulong) && other.convertsTo!(ulong))
1054181254a7Smrg                 result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
1055181254a7Smrg             else
1056181254a7Smrg                 result = mixin("get!(long) " ~ op ~ " other.get!(long)");
1057181254a7Smrg         }
1058181254a7Smrg         else
1059181254a7Smrg         {
1060181254a7Smrg             if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
1061181254a7Smrg                 result = mixin("get!(uint) " ~ op ~ " other");
1062181254a7Smrg             else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
1063181254a7Smrg                 result = mixin("get!(int) " ~ op ~ " other");
1064181254a7Smrg             else if (is(typeof(T.max) : ulong) && T.min == 0
1065181254a7Smrg                      && convertsTo!(ulong))
1066181254a7Smrg                 result = mixin("get!(ulong) " ~ op ~ " other");
1067181254a7Smrg             else
1068181254a7Smrg                 result = mixin("get!(long) " ~ op ~ " other");
1069181254a7Smrg         }
1070181254a7Smrg         return result;
1071181254a7Smrg     }
1072181254a7Smrg 
1073181254a7Smrg     /**
1074*b1e83836Smrg      * Arithmetic between `VariantN` objects and numeric
1075*b1e83836Smrg      * values. All arithmetic operations return a `VariantN`
1076181254a7Smrg      * object typed depending on the types of both values
1077181254a7Smrg      * involved. The conversion rules mimic D's built-in rules for
1078181254a7Smrg      * arithmetic conversions.
1079181254a7Smrg      */
1080*b1e83836Smrg     VariantN opBinary(string op, T)(T rhs)
1081*b1e83836Smrg     if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "^^" || op == "%") &&
1082*b1e83836Smrg         is(typeof(opArithmetic!(T, op)(rhs))))
1083*b1e83836Smrg     { return opArithmetic!(T, op)(rhs); }
1084181254a7Smrg     ///ditto
1085*b1e83836Smrg     VariantN opBinary(string op, T)(T rhs)
1086*b1e83836Smrg     if ((op == "&" || op == "|" || op == "^" || op == ">>" || op == "<<" || op == ">>>") &&
1087*b1e83836Smrg         is(typeof(opLogic!(T, op)(rhs))))
1088*b1e83836Smrg     { return opLogic!(T, op)(rhs); }
1089181254a7Smrg     ///ditto
1090*b1e83836Smrg     VariantN opBinaryRight(string op, T)(T lhs)
1091*b1e83836Smrg     if ((op == "+" || op == "*") &&
1092*b1e83836Smrg         is(typeof(opArithmetic!(T, op)(lhs))))
1093*b1e83836Smrg     { return opArithmetic!(T, op)(lhs); }
1094181254a7Smrg     ///ditto
1095*b1e83836Smrg     VariantN opBinaryRight(string op, T)(T lhs)
1096*b1e83836Smrg     if ((op == "&" || op == "|" || op == "^") &&
1097*b1e83836Smrg         is(typeof(opLogic!(T, op)(lhs))))
1098*b1e83836Smrg     { return opLogic!(T, op)(lhs); }
1099181254a7Smrg     ///ditto
1100*b1e83836Smrg     VariantN opBinary(string op, T)(T rhs)
1101*b1e83836Smrg         if (op == "~")
1102181254a7Smrg     {
1103181254a7Smrg         auto temp = this;
1104181254a7Smrg         temp ~= rhs;
1105181254a7Smrg         return temp;
1106181254a7Smrg     }
1107181254a7Smrg     // ///ditto
1108*b1e83836Smrg     // VariantN opBinaryRight(string op, T)(T rhs)
1109*b1e83836Smrg     //     if (op == "~")
1110181254a7Smrg     // {
1111181254a7Smrg     //     VariantN temp = rhs;
1112181254a7Smrg     //     temp ~= this;
1113181254a7Smrg     //     return temp;
1114181254a7Smrg     // }
1115181254a7Smrg 
1116181254a7Smrg     ///ditto
1117*b1e83836Smrg     VariantN opOpAssign(string op, T)(T rhs)
1118*b1e83836Smrg     {
1119*b1e83836Smrg         static if (op != "~")
1120*b1e83836Smrg         {
1121*b1e83836Smrg             mixin("return this = this" ~ op ~ "rhs;");
1122*b1e83836Smrg         }
1123*b1e83836Smrg         else
1124181254a7Smrg         {
1125181254a7Smrg             auto toAppend = Variant(rhs);
1126181254a7Smrg             fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
1127181254a7Smrg             return this;
1128181254a7Smrg         }
1129*b1e83836Smrg     }
1130181254a7Smrg 
1131181254a7Smrg     /**
1132181254a7Smrg      * Array and associative array operations. If a $(D
1133181254a7Smrg      * VariantN) contains an (associative) array, it can be indexed
1134181254a7Smrg      * into. Otherwise, an exception is thrown.
1135181254a7Smrg      */
1136181254a7Smrg     inout(Variant) opIndex(K)(K i) inout
1137181254a7Smrg     {
1138181254a7Smrg         auto result = Variant(i);
1139181254a7Smrg         fptr(OpID.index, cast(ubyte[size]*) &store, &result) == 0 || assert(false);
1140181254a7Smrg         return result;
1141181254a7Smrg     }
1142181254a7Smrg 
1143181254a7Smrg     ///
1144*b1e83836Smrg     version (StdDdoc)
1145181254a7Smrg     @system unittest
1146181254a7Smrg     {
1147181254a7Smrg         Variant a = new int[10];
1148181254a7Smrg         a[5] = 42;
1149181254a7Smrg         assert(a[5] == 42);
1150181254a7Smrg         a[5] += 8;
1151181254a7Smrg         assert(a[5] == 50);
1152181254a7Smrg 
1153181254a7Smrg         int[int] hash = [ 42:24 ];
1154181254a7Smrg         a = hash;
1155181254a7Smrg         assert(a[42] == 24);
1156181254a7Smrg         a[42] /= 2;
1157181254a7Smrg         assert(a[42] == 12);
1158181254a7Smrg     }
1159181254a7Smrg 
1160181254a7Smrg     /// ditto
1161181254a7Smrg     Variant opIndexAssign(T, N)(T value, N i)
1162181254a7Smrg     {
1163181254a7Smrg         static if (AllowedTypes.length && !isInstanceOf!(.VariantN, T))
1164181254a7Smrg         {
1165181254a7Smrg             enum canAssign(U) = __traits(compiles, (U u){ u[i] = value; });
1166181254a7Smrg             static assert(anySatisfy!(canAssign, AllowedTypes),
1167181254a7Smrg                 "Cannot assign " ~ T.stringof ~ " to " ~ VariantN.stringof ~
1168181254a7Smrg                 " indexed with " ~ N.stringof);
1169181254a7Smrg         }
1170181254a7Smrg         Variant[2] args = [ Variant(value), Variant(i) ];
1171181254a7Smrg         fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
1172181254a7Smrg         return args[0];
1173181254a7Smrg     }
1174181254a7Smrg 
1175181254a7Smrg     /// ditto
1176181254a7Smrg     Variant opIndexOpAssign(string op, T, N)(T value, N i)
1177181254a7Smrg     {
1178181254a7Smrg         return opIndexAssign(mixin(`opIndex(i)` ~ op ~ `value`), i);
1179181254a7Smrg     }
1180181254a7Smrg 
1181*b1e83836Smrg     /** If the `VariantN` contains an (associative) array,
1182181254a7Smrg      * returns the _length of that array. Otherwise, throws an
1183181254a7Smrg      * exception.
1184181254a7Smrg      */
1185181254a7Smrg     @property size_t length()
1186181254a7Smrg     {
1187181254a7Smrg         return cast(size_t) fptr(OpID.length, &store, null);
1188181254a7Smrg     }
1189181254a7Smrg 
1190181254a7Smrg     /**
1191*b1e83836Smrg        If the `VariantN` contains an array, applies `dg` to each
1192181254a7Smrg        element of the array in turn. Otherwise, throws an exception.
1193181254a7Smrg      */
1194181254a7Smrg     int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))
1195181254a7Smrg     {
1196181254a7Smrg         alias A = Parameters!(Delegate)[0];
1197181254a7Smrg         if (type == typeid(A[]))
1198181254a7Smrg         {
1199181254a7Smrg             auto arr = get!(A[]);
1200181254a7Smrg             foreach (ref e; arr)
1201181254a7Smrg             {
1202181254a7Smrg                 if (dg(e)) return 1;
1203181254a7Smrg             }
1204181254a7Smrg         }
1205181254a7Smrg         else static if (is(A == VariantN))
1206181254a7Smrg         {
1207181254a7Smrg             foreach (i; 0 .. length)
1208181254a7Smrg             {
1209181254a7Smrg                 // @@@TODO@@@: find a better way to not confuse
1210181254a7Smrg                 // clients who think they change values stored in the
1211181254a7Smrg                 // Variant when in fact they are only changing tmp.
1212181254a7Smrg                 auto tmp = this[i];
1213181254a7Smrg                 debug scope(exit) assert(tmp == this[i]);
1214181254a7Smrg                 if (dg(tmp)) return 1;
1215181254a7Smrg             }
1216181254a7Smrg         }
1217181254a7Smrg         else
1218181254a7Smrg         {
1219181254a7Smrg             import std.conv : text;
1220181254a7Smrg             import std.exception : enforce;
1221181254a7Smrg             enforce(false, text("Variant type ", type,
1222181254a7Smrg                             " not iterable with values of type ",
1223181254a7Smrg                             A.stringof));
1224181254a7Smrg         }
1225181254a7Smrg         return 0;
1226181254a7Smrg     }
1227181254a7Smrg }
1228181254a7Smrg 
1229*b1e83836Smrg ///
1230*b1e83836Smrg @system unittest
1231*b1e83836Smrg {
1232*b1e83836Smrg     alias Var = VariantN!(maxSize!(int, double, string));
1233*b1e83836Smrg 
1234*b1e83836Smrg     Var a; // Must assign before use, otherwise exception ensues
1235*b1e83836Smrg     // Initialize with an integer; make the type int
1236*b1e83836Smrg     Var b = 42;
1237*b1e83836Smrg     assert(b.type == typeid(int));
1238*b1e83836Smrg     // Peek at the value
1239*b1e83836Smrg     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1240*b1e83836Smrg     // Automatically convert per language rules
1241*b1e83836Smrg     auto x = b.get!(real);
1242*b1e83836Smrg 
1243*b1e83836Smrg     // Assign any other type, including other variants
1244*b1e83836Smrg     a = b;
1245*b1e83836Smrg     a = 3.14;
1246*b1e83836Smrg     assert(a.type == typeid(double));
1247*b1e83836Smrg     // Implicit conversions work just as with built-in types
1248*b1e83836Smrg     assert(a < b);
1249*b1e83836Smrg     // Check for convertibility
1250*b1e83836Smrg     assert(!a.convertsTo!(int)); // double not convertible to int
1251*b1e83836Smrg     // Strings and all other arrays are supported
1252*b1e83836Smrg     a = "now I'm a string";
1253*b1e83836Smrg     assert(a == "now I'm a string");
1254*b1e83836Smrg }
1255*b1e83836Smrg 
1256*b1e83836Smrg /// can also assign arrays
1257*b1e83836Smrg @system unittest
1258*b1e83836Smrg {
1259*b1e83836Smrg     alias Var = VariantN!(maxSize!(int[]));
1260*b1e83836Smrg 
1261*b1e83836Smrg     Var a = new int[42];
1262*b1e83836Smrg     assert(a.length == 42);
1263*b1e83836Smrg     a[5] = 7;
1264*b1e83836Smrg     assert(a[5] == 7);
1265*b1e83836Smrg }
1266*b1e83836Smrg 
1267*b1e83836Smrg @safe unittest
1268*b1e83836Smrg {
1269*b1e83836Smrg     alias V = VariantN!24;
1270*b1e83836Smrg     const alignMask = V.alignof - 1;
1271*b1e83836Smrg     assert(V.sizeof == ((24 + (void*).sizeof + alignMask) & ~alignMask));
1272*b1e83836Smrg }
1273*b1e83836Smrg 
1274*b1e83836Smrg /// Can also assign class values
1275*b1e83836Smrg @system unittest
1276*b1e83836Smrg {
1277*b1e83836Smrg     alias Var = VariantN!(maxSize!(int*)); // classes are pointers
1278*b1e83836Smrg     Var a;
1279*b1e83836Smrg 
1280*b1e83836Smrg     class Foo {}
1281*b1e83836Smrg     auto foo = new Foo;
1282*b1e83836Smrg     a = foo;
1283*b1e83836Smrg     assert(*a.peek!(Foo) == foo); // and full type information is preserved
1284*b1e83836Smrg }
1285*b1e83836Smrg 
1286181254a7Smrg @system unittest
1287181254a7Smrg {
1288181254a7Smrg     import std.conv : to;
1289181254a7Smrg     Variant v;
foo()1290181254a7Smrg     int foo() { return 42; }
1291181254a7Smrg     v = &foo;
1292181254a7Smrg     assert(v() == 42);
1293181254a7Smrg 
bar(string s)1294181254a7Smrg     static int bar(string s) { return to!int(s); }
1295181254a7Smrg     v = &bar;
1296181254a7Smrg     assert(v("43") == 43);
1297181254a7Smrg }
1298181254a7Smrg 
1299181254a7Smrg @system unittest
1300181254a7Smrg {
1301181254a7Smrg     int[int] hash = [ 42:24 ];
1302181254a7Smrg     Variant v = hash;
1303181254a7Smrg     assert(v[42] == 24);
1304181254a7Smrg     v[42] = 5;
1305181254a7Smrg     assert(v[42] == 5);
1306181254a7Smrg }
1307181254a7Smrg 
1308*b1e83836Smrg // opIndex with static arrays, https://issues.dlang.org/show_bug.cgi?id=12771
1309181254a7Smrg @system unittest
1310181254a7Smrg {
1311181254a7Smrg     int[4] elements = [0, 1, 2, 3];
1312181254a7Smrg     Variant v = elements;
1313181254a7Smrg     assert(v == elements);
1314181254a7Smrg     assert(v[2] == 2);
1315181254a7Smrg     assert(v[3] == 3);
1316181254a7Smrg     v[2] = 6;
1317181254a7Smrg     assert(v[2] == 6);
1318181254a7Smrg     assert(v != elements);
1319181254a7Smrg }
1320181254a7Smrg 
1321181254a7Smrg @system unittest
1322181254a7Smrg {
1323181254a7Smrg     import std.exception : assertThrown;
1324181254a7Smrg     Algebraic!(int[]) v = [2, 2];
1325181254a7Smrg 
1326181254a7Smrg     assert(v == [2, 2]);
1327181254a7Smrg     v[0] = 1;
1328181254a7Smrg     assert(v[0] == 1);
1329181254a7Smrg     assert(v != [2, 2]);
1330181254a7Smrg 
1331181254a7Smrg     // opIndexAssign from Variant
1332181254a7Smrg     v[1] = v[0];
1333181254a7Smrg     assert(v[1] == 1);
1334181254a7Smrg 
1335181254a7Smrg     static assert(!__traits(compiles, (v[1] = null)));
1336181254a7Smrg     assertThrown!VariantException(v[1] = Variant(null));
1337181254a7Smrg }
1338181254a7Smrg 
1339*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=10879
1340*b1e83836Smrg @system unittest
1341*b1e83836Smrg {
1342*b1e83836Smrg     int[10] arr = [1,2,3,4,5,6,7,8,9,10];
1343*b1e83836Smrg     Variant v1 = arr;
1344*b1e83836Smrg     Variant v2;
1345*b1e83836Smrg     v2 = arr;
1346*b1e83836Smrg     assert(v1 == arr);
1347*b1e83836Smrg     assert(v2 == arr);
foreach(i,e;arr)1348*b1e83836Smrg     foreach (i, e; arr)
1349*b1e83836Smrg     {
1350*b1e83836Smrg         assert(v1[i] == e);
1351*b1e83836Smrg         assert(v2[i] == e);
1352*b1e83836Smrg     }
1353*b1e83836Smrg     static struct LargeStruct
1354*b1e83836Smrg     {
1355*b1e83836Smrg         int[100] data;
1356*b1e83836Smrg     }
1357*b1e83836Smrg     LargeStruct ls;
1358*b1e83836Smrg     ls.data[] = 4;
1359*b1e83836Smrg     v1 = ls;
1360*b1e83836Smrg     Variant v3 = ls;
1361*b1e83836Smrg     assert(v1 == ls);
1362*b1e83836Smrg     assert(v3 == ls);
1363*b1e83836Smrg }
1364*b1e83836Smrg 
1365*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=8195
1366181254a7Smrg @system unittest
1367181254a7Smrg {
1368181254a7Smrg     struct S
1369181254a7Smrg     {
1370181254a7Smrg         int a;
1371181254a7Smrg         long b;
1372181254a7Smrg         string c;
1373181254a7Smrg         real d = 0.0;
1374181254a7Smrg         bool e;
1375181254a7Smrg     }
1376181254a7Smrg 
1377181254a7Smrg     static assert(S.sizeof >= Variant.sizeof);
1378181254a7Smrg     alias Types = AliasSeq!(string, int, S);
1379181254a7Smrg     alias MyVariant = VariantN!(maxSize!Types, Types);
1380181254a7Smrg 
1381181254a7Smrg     auto v = MyVariant(S.init);
1382181254a7Smrg     assert(v == S.init);
1383181254a7Smrg }
1384181254a7Smrg 
1385*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=10961
1386181254a7Smrg @system unittest
1387181254a7Smrg {
1388181254a7Smrg     // Primarily test that we can assign a void[] to a Variant.
1389181254a7Smrg     void[] elements = cast(void[])[1, 2, 3];
1390181254a7Smrg     Variant v = elements;
1391181254a7Smrg     void[] returned = v.get!(void[]);
1392181254a7Smrg     assert(returned == elements);
1393181254a7Smrg }
1394181254a7Smrg 
1395*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=13352
1396181254a7Smrg @system unittest
1397181254a7Smrg {
1398181254a7Smrg     alias TP = Algebraic!(long);
1399181254a7Smrg     auto a = TP(1L);
1400181254a7Smrg     auto b = TP(2L);
1401181254a7Smrg     assert(!TP.allowed!ulong);
1402181254a7Smrg     assert(a + b == 3L);
1403181254a7Smrg     assert(a + 2 == 3L);
1404181254a7Smrg     assert(1 + b == 3L);
1405181254a7Smrg 
1406181254a7Smrg     alias TP2 = Algebraic!(long, string);
1407181254a7Smrg     auto c = TP2(3L);
1408181254a7Smrg     assert(a + c == 4L);
1409181254a7Smrg }
1410181254a7Smrg 
1411*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=13354
1412181254a7Smrg @system unittest
1413181254a7Smrg {
1414181254a7Smrg     alias A = Algebraic!(string[]);
1415181254a7Smrg     A a = ["a", "b"];
1416181254a7Smrg     assert(a[0] == "a");
1417181254a7Smrg     assert(a[1] == "b");
1418181254a7Smrg     a[1] = "c";
1419181254a7Smrg     assert(a[1] == "c");
1420181254a7Smrg 
1421181254a7Smrg     alias AA = Algebraic!(int[string]);
1422181254a7Smrg     AA aa = ["a": 1, "b": 2];
1423181254a7Smrg     assert(aa["a"] == 1);
1424181254a7Smrg     assert(aa["b"] == 2);
1425181254a7Smrg     aa["b"] = 3;
1426181254a7Smrg     assert(aa["b"] == 3);
1427181254a7Smrg }
1428181254a7Smrg 
1429*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=14198
1430181254a7Smrg @system unittest
1431181254a7Smrg {
1432181254a7Smrg     Variant a = true;
1433181254a7Smrg     assert(a.type == typeid(bool));
1434181254a7Smrg }
1435181254a7Smrg 
1436*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=14233
1437181254a7Smrg @system unittest
1438181254a7Smrg {
1439181254a7Smrg     alias Atom = Algebraic!(string, This[]);
1440181254a7Smrg 
1441181254a7Smrg     Atom[] values = [];
1442181254a7Smrg     auto a = Atom(values);
1443181254a7Smrg }
1444181254a7Smrg 
1445181254a7Smrg pure nothrow @nogc
1446181254a7Smrg @system unittest
1447181254a7Smrg {
1448181254a7Smrg     Algebraic!(int, double) a;
1449181254a7Smrg     a = 100;
1450181254a7Smrg     a = 1.0;
1451181254a7Smrg }
1452181254a7Smrg 
1453*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=14457
1454181254a7Smrg @system unittest
1455181254a7Smrg {
1456181254a7Smrg     alias A = Algebraic!(int, float, double);
1457181254a7Smrg     alias B = Algebraic!(int, float);
1458181254a7Smrg 
1459181254a7Smrg     A a = 1;
1460181254a7Smrg     B b = 6f;
1461181254a7Smrg     a = b;
1462181254a7Smrg 
1463181254a7Smrg     assert(a.type == typeid(float));
1464181254a7Smrg     assert(a.get!float == 6f);
1465181254a7Smrg }
1466181254a7Smrg 
1467*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=14585
1468181254a7Smrg @system unittest
1469181254a7Smrg {
1470181254a7Smrg     static struct S
1471181254a7Smrg     {
1472181254a7Smrg         int x = 42;
~thisS1473181254a7Smrg         ~this() {assert(x == 42);}
1474181254a7Smrg     }
1475181254a7Smrg     Variant(S()).get!S;
1476181254a7Smrg }
1477181254a7Smrg 
1478*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=14586
1479181254a7Smrg @system unittest
1480181254a7Smrg {
1481181254a7Smrg     const Variant v = new immutable Object;
1482181254a7Smrg     v.get!(immutable Object);
1483181254a7Smrg }
1484181254a7Smrg 
1485181254a7Smrg @system unittest
1486181254a7Smrg {
1487181254a7Smrg     static struct S
1488181254a7Smrg     {
opCastS1489181254a7Smrg         T opCast(T)() {assert(false);}
1490181254a7Smrg     }
1491181254a7Smrg     Variant v = S();
1492181254a7Smrg     v.get!S;
1493181254a7Smrg }
1494181254a7Smrg 
1495*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=13262
1496*b1e83836Smrg @system unittest
1497*b1e83836Smrg {
fun(T)1498*b1e83836Smrg     static void fun(T)(Variant v){
1499*b1e83836Smrg         T x;
1500*b1e83836Smrg         v = x;
1501*b1e83836Smrg         auto r = v.get!(T);
1502*b1e83836Smrg     }
1503*b1e83836Smrg     Variant v;
1504*b1e83836Smrg     fun!(shared(int))(v);
1505*b1e83836Smrg     fun!(shared(int)[])(v);
1506*b1e83836Smrg 
1507*b1e83836Smrg     static struct S1
1508*b1e83836Smrg     {
1509*b1e83836Smrg         int c;
1510*b1e83836Smrg         string a;
1511*b1e83836Smrg     }
1512*b1e83836Smrg 
1513*b1e83836Smrg     static struct S2
1514*b1e83836Smrg     {
1515*b1e83836Smrg         string a;
1516*b1e83836Smrg         shared int[] b;
1517*b1e83836Smrg     }
1518*b1e83836Smrg 
1519*b1e83836Smrg     static struct S3
1520*b1e83836Smrg     {
1521*b1e83836Smrg         string a;
1522*b1e83836Smrg         shared int[] b;
1523*b1e83836Smrg         int c;
1524*b1e83836Smrg     }
1525*b1e83836Smrg 
1526*b1e83836Smrg     fun!(S1)(v);
1527*b1e83836Smrg     fun!(shared(S1))(v);
1528*b1e83836Smrg     fun!(S2)(v);
1529*b1e83836Smrg     fun!(shared(S2))(v);
1530*b1e83836Smrg     fun!(S3)(v);
1531*b1e83836Smrg     fun!(shared(S3))(v);
1532*b1e83836Smrg 
1533*b1e83836Smrg     // ensure structs that are shared, but don't have shared postblits
1534*b1e83836Smrg     // can't be used.
1535*b1e83836Smrg     static struct S4
1536*b1e83836Smrg     {
1537*b1e83836Smrg         int x;
thisS41538*b1e83836Smrg         this(this) {x = 0;}
1539*b1e83836Smrg     }
1540*b1e83836Smrg 
1541*b1e83836Smrg     fun!(S4)(v);
1542*b1e83836Smrg     static assert(!is(typeof(fun!(shared(S4))(v))));
1543*b1e83836Smrg }
1544*b1e83836Smrg 
1545*b1e83836Smrg @safe unittest
1546*b1e83836Smrg {
1547*b1e83836Smrg     Algebraic!(int) x;
1548*b1e83836Smrg 
1549*b1e83836Smrg     static struct SafeS
1550*b1e83836Smrg     {
~thisSafeS1551*b1e83836Smrg         @safe ~this() {}
1552*b1e83836Smrg     }
1553*b1e83836Smrg 
1554*b1e83836Smrg     Algebraic!(SafeS) y;
1555*b1e83836Smrg }
1556*b1e83836Smrg 
1557*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=19986
1558*b1e83836Smrg @system unittest
1559*b1e83836Smrg {
1560*b1e83836Smrg     VariantN!32 v;
1561*b1e83836Smrg     v = const(ubyte[33]).init;
1562*b1e83836Smrg 
1563*b1e83836Smrg     struct S
1564*b1e83836Smrg     {
1565*b1e83836Smrg         ubyte[33] s;
1566*b1e83836Smrg     }
1567*b1e83836Smrg 
1568*b1e83836Smrg     VariantN!32 v2;
1569*b1e83836Smrg     v2 = const(S).init;
1570*b1e83836Smrg }
1571*b1e83836Smrg 
1572*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=21021
1573*b1e83836Smrg @system unittest
1574*b1e83836Smrg {
1575*b1e83836Smrg     static struct S
1576*b1e83836Smrg     {
1577*b1e83836Smrg         int h;
1578*b1e83836Smrg         int[5] array;
1579*b1e83836Smrg         alias h this;
1580*b1e83836Smrg     }
1581*b1e83836Smrg 
1582*b1e83836Smrg     S msg;
1583*b1e83836Smrg     msg.array[] = 3;
1584*b1e83836Smrg     Variant a = msg;
1585*b1e83836Smrg     auto other = a.get!S;
1586*b1e83836Smrg     assert(msg.array[0] == 3);
1587*b1e83836Smrg     assert(other.array[0] == 3);
1588*b1e83836Smrg }
1589*b1e83836Smrg 
1590*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=21231
1591*b1e83836Smrg // Compatibility with -preview=fieldwise
1592*b1e83836Smrg @system unittest
1593*b1e83836Smrg {
1594*b1e83836Smrg     static struct Empty
1595*b1e83836Smrg     {
opCmpEmpty1596*b1e83836Smrg         bool opCmp(const scope ref Empty) const
1597*b1e83836Smrg         { return false; }
1598*b1e83836Smrg     }
1599*b1e83836Smrg 
1600*b1e83836Smrg     Empty a, b;
1601*b1e83836Smrg     assert(a == b);
1602*b1e83836Smrg     assert(!(a < b));
1603*b1e83836Smrg 
1604*b1e83836Smrg     VariantN!(4, Empty) v = a;
1605*b1e83836Smrg     assert(v == b);
1606*b1e83836Smrg     assert(!(v < b));
1607*b1e83836Smrg }
1608*b1e83836Smrg 
1609*b1e83836Smrg // Compatibility with -preview=fieldwise
1610*b1e83836Smrg @system unittest
1611*b1e83836Smrg {
1612*b1e83836Smrg     static struct Empty
1613*b1e83836Smrg     {
opEqualsEmpty1614*b1e83836Smrg         bool opEquals(const scope ref Empty) const
1615*b1e83836Smrg         { return false; }
1616*b1e83836Smrg     }
1617*b1e83836Smrg 
1618*b1e83836Smrg     Empty a, b;
1619*b1e83836Smrg     assert(a != b);
1620*b1e83836Smrg 
1621*b1e83836Smrg     VariantN!(4, Empty) v = a;
1622*b1e83836Smrg     assert(v != b);
1623*b1e83836Smrg }
1624*b1e83836Smrg 
1625*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=22647
1626*b1e83836Smrg // Can compare with 'null'
1627*b1e83836Smrg @system unittest
1628*b1e83836Smrg {
1629*b1e83836Smrg     static struct Bar
1630*b1e83836Smrg     {
1631*b1e83836Smrg         int* ptr;
1632*b1e83836Smrg         alias ptr this;
1633*b1e83836Smrg     }
1634*b1e83836Smrg 
1635*b1e83836Smrg     static class Foo {}
1636*b1e83836Smrg     int* iptr;
1637*b1e83836Smrg     int[] arr;
1638*b1e83836Smrg 
1639*b1e83836Smrg     Variant v = Foo.init; // 'null'
1640*b1e83836Smrg     assert(v != null); // can only compare objects with 'null' by using 'is'
1641*b1e83836Smrg 
1642*b1e83836Smrg     v = iptr;
1643*b1e83836Smrg     assert(v == null); // pointers can be compared with 'null'
1644*b1e83836Smrg 
1645*b1e83836Smrg     v = arr;
1646*b1e83836Smrg     assert(v == null); // arrays can be compared with 'null'
1647*b1e83836Smrg 
1648*b1e83836Smrg     v = "";
1649*b1e83836Smrg     assert(v == null); // strings are arrays, an empty string is considered 'null'
1650*b1e83836Smrg 
1651*b1e83836Smrg     v = Bar.init;
1652*b1e83836Smrg     assert(v == null); // works with alias this
1653*b1e83836Smrg 
1654*b1e83836Smrg     v = [3];
1655*b1e83836Smrg     assert(v != null);
1656*b1e83836Smrg     assert(v > null);
1657*b1e83836Smrg     assert(v >= null);
1658*b1e83836Smrg     assert(!(v < null));
1659*b1e83836Smrg }
1660181254a7Smrg 
1661181254a7Smrg /**
1662181254a7Smrg _Algebraic data type restricted to a closed set of possible
1663181254a7Smrg types. It's an alias for $(LREF VariantN) with an
1664181254a7Smrg appropriately-constructed maximum size. `Algebraic` is
1665181254a7Smrg useful when it is desirable to restrict what a discriminated type
1666181254a7Smrg could hold to the end of defining simpler and more efficient
1667181254a7Smrg manipulation.
1668181254a7Smrg 
1669*b1e83836Smrg $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
1670*b1e83836Smrg code. Instead, use $(REF SumType, std,sumtype).)
1671181254a7Smrg */
Algebraic(T...)1672181254a7Smrg template Algebraic(T...)
1673181254a7Smrg {
1674181254a7Smrg     alias Algebraic = VariantN!(maxSize!T, T);
1675181254a7Smrg }
1676181254a7Smrg 
1677181254a7Smrg ///
1678181254a7Smrg @system unittest
1679181254a7Smrg {
1680181254a7Smrg     auto v = Algebraic!(int, double, string)(5);
1681181254a7Smrg     assert(v.peek!(int));
1682181254a7Smrg     v = 3.14;
1683181254a7Smrg     assert(v.peek!(double));
1684181254a7Smrg     // auto x = v.peek!(long); // won't compile, type long not allowed
1685181254a7Smrg     // v = '1'; // won't compile, type char not allowed
1686181254a7Smrg }
1687181254a7Smrg 
1688181254a7Smrg /**
1689181254a7Smrg $(H4 Self-Referential Types)
1690181254a7Smrg 
1691181254a7Smrg A useful and popular use of algebraic data structures is for defining $(LUCKY
1692181254a7Smrg self-referential data structures), i.e. structures that embed references to
1693181254a7Smrg values of their own type within.
1694181254a7Smrg 
1695181254a7Smrg This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1696181254a7Smrg reference to the type being defined is needed. The `Algebraic` instantiation
1697181254a7Smrg will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1698181254a7Smrg alpha renaming) on its constituent types, replacing `This`
1699181254a7Smrg with the self-referenced type. The structure of the type involving `This` may
1700181254a7Smrg be arbitrarily complex.
1701181254a7Smrg */
1702181254a7Smrg @system unittest
1703181254a7Smrg {
1704181254a7Smrg     import std.typecons : Tuple, tuple;
1705181254a7Smrg 
1706181254a7Smrg     // A tree is either a leaf or a branch of two other trees
1707181254a7Smrg     alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
1708181254a7Smrg     Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
1709181254a7Smrg     Tree!int* right = tree.get!1[1];
1710181254a7Smrg     assert(*right == 43);
1711181254a7Smrg 
1712181254a7Smrg     // An object is a double, a string, or a hash of objects
1713181254a7Smrg     alias Obj = Algebraic!(double, string, This[string]);
1714181254a7Smrg     Obj obj = "hello";
1715181254a7Smrg     assert(obj.get!1 == "hello");
1716181254a7Smrg     obj = 42.0;
1717181254a7Smrg     assert(obj.get!0 == 42);
1718181254a7Smrg     obj = ["customer": Obj("John"), "paid": Obj(23.95)];
1719181254a7Smrg     assert(obj.get!2["customer"] == "John");
1720181254a7Smrg }
1721181254a7Smrg 
1722*b1e83836Smrg private struct FakeComplexReal
1723*b1e83836Smrg {
1724*b1e83836Smrg     real re, im;
1725*b1e83836Smrg }
1726*b1e83836Smrg 
1727181254a7Smrg /**
1728181254a7Smrg Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1729181254a7Smrg `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1730181254a7Smrg to hold all of D's predefined types unboxed, including all numeric types,
1731181254a7Smrg pointers, delegates, and class references.  You may want to use
1732*b1e83836Smrg `VariantN` directly with a different maximum size either for
1733181254a7Smrg storing larger types unboxed, or for saving memory.
1734181254a7Smrg  */
1735*b1e83836Smrg alias Variant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()));
1736*b1e83836Smrg 
1737*b1e83836Smrg ///
1738*b1e83836Smrg @system unittest
1739*b1e83836Smrg {
1740*b1e83836Smrg     Variant a; // Must assign before use, otherwise exception ensues
1741*b1e83836Smrg     // Initialize with an integer; make the type int
1742*b1e83836Smrg     Variant b = 42;
1743*b1e83836Smrg     assert(b.type == typeid(int));
1744*b1e83836Smrg     // Peek at the value
1745*b1e83836Smrg     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1746*b1e83836Smrg     // Automatically convert per language rules
1747*b1e83836Smrg     auto x = b.get!(real);
1748*b1e83836Smrg 
1749*b1e83836Smrg     // Assign any other type, including other variants
1750*b1e83836Smrg     a = b;
1751*b1e83836Smrg     a = 3.14;
1752*b1e83836Smrg     assert(a.type == typeid(double));
1753*b1e83836Smrg     // Implicit conversions work just as with built-in types
1754*b1e83836Smrg     assert(a < b);
1755*b1e83836Smrg     // Check for convertibility
1756*b1e83836Smrg     assert(!a.convertsTo!(int)); // double not convertible to int
1757*b1e83836Smrg     // Strings and all other arrays are supported
1758*b1e83836Smrg     a = "now I'm a string";
1759*b1e83836Smrg     assert(a == "now I'm a string");
1760*b1e83836Smrg }
1761*b1e83836Smrg 
1762*b1e83836Smrg /// can also assign arrays
1763*b1e83836Smrg @system unittest
1764*b1e83836Smrg {
1765*b1e83836Smrg     Variant a = new int[42];
1766*b1e83836Smrg     assert(a.length == 42);
1767*b1e83836Smrg     a[5] = 7;
1768*b1e83836Smrg     assert(a[5] == 7);
1769*b1e83836Smrg }
1770*b1e83836Smrg 
1771*b1e83836Smrg /// Can also assign class values
1772*b1e83836Smrg @system unittest
1773*b1e83836Smrg {
1774*b1e83836Smrg     Variant a;
1775*b1e83836Smrg 
1776*b1e83836Smrg     class Foo {}
1777*b1e83836Smrg     auto foo = new Foo;
1778*b1e83836Smrg     a = foo;
1779*b1e83836Smrg     assert(*a.peek!(Foo) == foo); // and full type information is preserved
1780*b1e83836Smrg }
1781181254a7Smrg 
1782181254a7Smrg /**
1783*b1e83836Smrg  * Returns an array of variants constructed from `args`.
1784181254a7Smrg  *
1785*b1e83836Smrg  * This is by design. During construction the `Variant` needs
1786181254a7Smrg  * static type information about the type being held, so as to store a
1787181254a7Smrg  * pointer to function for fast retrieval.
1788181254a7Smrg  */
variantArray(T...)1789181254a7Smrg Variant[] variantArray(T...)(T args)
1790181254a7Smrg {
1791181254a7Smrg     Variant[] result;
1792181254a7Smrg     foreach (arg; args)
1793181254a7Smrg     {
1794181254a7Smrg         result ~= Variant(arg);
1795181254a7Smrg     }
1796181254a7Smrg     return result;
1797181254a7Smrg }
1798181254a7Smrg 
1799181254a7Smrg ///
1800181254a7Smrg @system unittest
1801181254a7Smrg {
1802181254a7Smrg     auto a = variantArray(1, 3.14, "Hi!");
1803181254a7Smrg     assert(a[1] == 3.14);
1804181254a7Smrg     auto b = Variant(a); // variant array as variant
1805181254a7Smrg     assert(b[1] == 3.14);
1806181254a7Smrg }
1807181254a7Smrg 
1808181254a7Smrg /**
1809181254a7Smrg  * Thrown in three cases:
1810181254a7Smrg  *
1811181254a7Smrg  * $(OL $(LI An uninitialized `Variant` is used in any way except
1812*b1e83836Smrg  * assignment and `hasValue`;) $(LI A `get` or
1813*b1e83836Smrg  * `coerce` is attempted with an incompatible target type;)
1814*b1e83836Smrg  * $(LI A comparison between `Variant` objects of
1815181254a7Smrg  * incompatible types is attempted.))
1816181254a7Smrg  *
1817181254a7Smrg  */
1818181254a7Smrg 
1819181254a7Smrg // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
1820181254a7Smrg static class VariantException : Exception
1821181254a7Smrg {
1822181254a7Smrg     /// The source type in the conversion or comparison
1823181254a7Smrg     TypeInfo source;
1824181254a7Smrg     /// The target type in the conversion or comparison
1825181254a7Smrg     TypeInfo target;
this(string s)1826181254a7Smrg     this(string s)
1827181254a7Smrg     {
1828181254a7Smrg         super(s);
1829181254a7Smrg     }
this(TypeInfo source,TypeInfo target)1830181254a7Smrg     this(TypeInfo source, TypeInfo target)
1831181254a7Smrg     {
1832181254a7Smrg         super("Variant: attempting to use incompatible types "
1833181254a7Smrg                             ~ source.toString()
1834181254a7Smrg                             ~ " and " ~ target.toString());
1835181254a7Smrg         this.source = source;
1836181254a7Smrg         this.target = target;
1837181254a7Smrg     }
1838181254a7Smrg }
1839181254a7Smrg 
1840*b1e83836Smrg ///
1841*b1e83836Smrg @system unittest
1842*b1e83836Smrg {
1843*b1e83836Smrg     import std.exception : assertThrown;
1844*b1e83836Smrg 
1845*b1e83836Smrg     Variant v;
1846*b1e83836Smrg 
1847*b1e83836Smrg     // uninitialized use
1848*b1e83836Smrg     assertThrown!VariantException(v + 1);
1849*b1e83836Smrg     assertThrown!VariantException(v.length);
1850*b1e83836Smrg 
1851*b1e83836Smrg     // .get with an incompatible target type
1852*b1e83836Smrg     assertThrown!VariantException(Variant("a").get!int);
1853*b1e83836Smrg 
1854*b1e83836Smrg     // comparison between incompatible types
1855*b1e83836Smrg     assertThrown!VariantException(Variant(3) < Variant("a"));
1856*b1e83836Smrg }
1857*b1e83836Smrg 
1858181254a7Smrg @system unittest
1859181254a7Smrg {
1860181254a7Smrg     alias W1 = This2Variant!(char, int, This[int]);
1861181254a7Smrg     alias W2 = AliasSeq!(int, char[int]);
1862181254a7Smrg     static assert(is(W1 == W2));
1863181254a7Smrg 
1864181254a7Smrg     alias var_t = Algebraic!(void, string);
1865181254a7Smrg     var_t foo = "quux";
1866181254a7Smrg }
1867181254a7Smrg 
1868181254a7Smrg @system unittest
1869181254a7Smrg {
1870181254a7Smrg      alias A = Algebraic!(real, This[], This[int], This[This]);
1871181254a7Smrg      A v1, v2, v3;
1872181254a7Smrg      v2 = 5.0L;
1873181254a7Smrg      v3 = 42.0L;
1874181254a7Smrg      //v1 = [ v2 ][];
1875181254a7Smrg       auto v = v1.peek!(A[]);
1876181254a7Smrg      //writeln(v[0]);
1877181254a7Smrg      v1 = [ 9 : v3 ];
1878181254a7Smrg      //writeln(v1);
1879181254a7Smrg      v1 = [ v3 : v3 ];
1880181254a7Smrg      //writeln(v1);
1881181254a7Smrg }
1882181254a7Smrg 
1883181254a7Smrg @system unittest
1884181254a7Smrg {
1885181254a7Smrg     import std.conv : ConvException;
1886181254a7Smrg     import std.exception : assertThrown, collectException;
1887181254a7Smrg     // try it with an oddly small size
1888181254a7Smrg     VariantN!(1) test;
1889181254a7Smrg     assert(test.size > 1);
1890181254a7Smrg 
1891181254a7Smrg     // variantArray tests
1892181254a7Smrg     auto heterogeneous = variantArray(1, 4.5, "hi");
1893181254a7Smrg     assert(heterogeneous.length == 3);
1894181254a7Smrg     auto variantArrayAsVariant = Variant(heterogeneous);
1895181254a7Smrg     assert(variantArrayAsVariant[0] == 1);
1896181254a7Smrg     assert(variantArrayAsVariant.length == 3);
1897181254a7Smrg 
1898181254a7Smrg     // array tests
1899181254a7Smrg     auto arr = Variant([1.2].dup);
1900181254a7Smrg     auto e = arr[0];
1901181254a7Smrg     assert(e == 1.2);
1902181254a7Smrg     arr[0] = 2.0;
1903181254a7Smrg     assert(arr[0] == 2);
1904181254a7Smrg     arr ~= 4.5;
1905181254a7Smrg     assert(arr[1] == 4.5);
1906181254a7Smrg 
1907181254a7Smrg     // general tests
1908181254a7Smrg     Variant a;
1909181254a7Smrg     auto b = Variant(5);
1910181254a7Smrg     assert(!b.peek!(real) && b.peek!(int));
1911181254a7Smrg     // assign
1912181254a7Smrg     a = *b.peek!(int);
1913181254a7Smrg     // comparison
1914181254a7Smrg     assert(a == b, a.type.toString() ~ " " ~ b.type.toString());
1915181254a7Smrg     auto c = Variant("this is a string");
1916181254a7Smrg     assert(a != c);
1917181254a7Smrg     // comparison via implicit conversions
1918181254a7Smrg     a = 42; b = 42.0; assert(a == b);
1919181254a7Smrg 
1920181254a7Smrg     // try failing conversions
1921181254a7Smrg     bool failed = false;
1922181254a7Smrg     try
1923181254a7Smrg     {
1924181254a7Smrg         auto d = c.get!(int);
1925181254a7Smrg     }
catch(Exception e)1926181254a7Smrg     catch (Exception e)
1927181254a7Smrg     {
1928181254a7Smrg         //writeln(stderr, e.toString);
1929181254a7Smrg         failed = true;
1930181254a7Smrg     }
1931181254a7Smrg     assert(failed); // :o)
1932181254a7Smrg 
1933181254a7Smrg     // toString tests
1934181254a7Smrg     a = Variant(42); assert(a.toString() == "42");
1935181254a7Smrg     a = Variant(42.22); assert(a.toString() == "42.22");
1936181254a7Smrg 
1937181254a7Smrg     // coerce tests
1938181254a7Smrg     a = Variant(42.22); assert(a.coerce!(int) == 42);
1939181254a7Smrg     a = cast(short) 5; assert(a.coerce!(double) == 5);
1940181254a7Smrg     a = Variant("10"); assert(a.coerce!int == 10);
1941181254a7Smrg 
1942181254a7Smrg     a = Variant(1);
1943181254a7Smrg     assert(a.coerce!bool);
1944181254a7Smrg     a = Variant(0);
1945181254a7Smrg     assert(!a.coerce!bool);
1946181254a7Smrg 
1947181254a7Smrg     a = Variant(1.0);
1948181254a7Smrg     assert(a.coerce!bool);
1949181254a7Smrg     a = Variant(0.0);
1950181254a7Smrg     assert(!a.coerce!bool);
1951181254a7Smrg     a = Variant(float.init);
1952181254a7Smrg     assertThrown!ConvException(a.coerce!bool);
1953181254a7Smrg 
1954181254a7Smrg     a = Variant("true");
1955181254a7Smrg     assert(a.coerce!bool);
1956181254a7Smrg     a = Variant("false");
1957181254a7Smrg     assert(!a.coerce!bool);
1958181254a7Smrg     a = Variant("");
1959181254a7Smrg     assertThrown!ConvException(a.coerce!bool);
1960181254a7Smrg 
1961181254a7Smrg     // Object tests
1962181254a7Smrg     class B1 {}
1963181254a7Smrg     class B2 : B1 {}
1964181254a7Smrg     a = new B2;
1965181254a7Smrg     assert(a.coerce!(B1) !is null);
1966181254a7Smrg     a = new B1;
1967181254a7Smrg     assert(collectException(a.coerce!(B2) is null));
1968181254a7Smrg     a = cast(Object) new B2; // lose static type info; should still work
1969181254a7Smrg     assert(a.coerce!(B2) !is null);
1970181254a7Smrg 
1971181254a7Smrg //     struct Big { int a[45]; }
1972181254a7Smrg //     a = Big.init;
1973181254a7Smrg 
1974181254a7Smrg     // hash
1975181254a7Smrg     assert(a.toHash() != 0);
1976181254a7Smrg }
1977181254a7Smrg 
1978181254a7Smrg // tests adapted from
1979181254a7Smrg // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601
1980181254a7Smrg @system unittest
1981181254a7Smrg {
1982181254a7Smrg     Variant v;
1983181254a7Smrg 
1984181254a7Smrg     assert(!v.hasValue);
1985181254a7Smrg     v = 42;
1986181254a7Smrg     assert( v.peek!(int) );
1987181254a7Smrg     assert( v.convertsTo!(long) );
1988181254a7Smrg     assert( v.get!(int) == 42 );
1989181254a7Smrg     assert( v.get!(long) == 42L );
1990181254a7Smrg     assert( v.get!(ulong) == 42uL );
1991181254a7Smrg 
1992181254a7Smrg     v = "Hello, World!";
1993181254a7Smrg     assert( v.peek!(string) );
1994181254a7Smrg 
1995181254a7Smrg     assert( v.get!(string) == "Hello, World!" );
1996181254a7Smrg     assert(!is(char[] : wchar[]));
1997181254a7Smrg     assert( !v.convertsTo!(wchar[]) );
1998181254a7Smrg     assert( v.get!(string) == "Hello, World!" );
1999181254a7Smrg 
2000181254a7Smrg     // Literal arrays are dynamically-typed
2001181254a7Smrg     v = cast(int[4]) [1,2,3,4];
2002181254a7Smrg     assert( v.peek!(int[4]) );
2003181254a7Smrg     assert( v.get!(int[4]) == [1,2,3,4] );
2004181254a7Smrg 
2005181254a7Smrg     {
2006181254a7Smrg          v = [1,2,3,4,5];
2007181254a7Smrg          assert( v.peek!(int[]) );
2008181254a7Smrg          assert( v.get!(int[]) == [1,2,3,4,5] );
2009181254a7Smrg     }
2010181254a7Smrg 
2011181254a7Smrg     v = 3.1413;
2012181254a7Smrg     assert( v.peek!(double) );
2013181254a7Smrg     assert( v.convertsTo!(real) );
2014181254a7Smrg     //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT
2015*b1e83836Smrg     assert( v.convertsTo!(float) );
2016181254a7Smrg     assert( *v.peek!(double) == 3.1413 );
2017181254a7Smrg 
2018181254a7Smrg     auto u = Variant(v);
2019181254a7Smrg     assert( u.peek!(double) );
2020181254a7Smrg     assert( *u.peek!(double) == 3.1413 );
2021181254a7Smrg 
2022181254a7Smrg     // operators
2023181254a7Smrg     v = 38;
2024181254a7Smrg     assert( v + 4 == 42 );
2025181254a7Smrg     assert( 4 + v == 42 );
2026181254a7Smrg     assert( v - 4 == 34 );
2027181254a7Smrg     assert( Variant(4) - v == -34 );
2028181254a7Smrg     assert( v * 2 == 76 );
2029181254a7Smrg     assert( 2 * v == 76 );
2030181254a7Smrg     assert( v / 2 == 19 );
2031181254a7Smrg     assert( Variant(2) / v == 0 );
2032181254a7Smrg     assert( v % 2 == 0 );
2033181254a7Smrg     assert( Variant(2) % v == 2 );
2034181254a7Smrg     assert( (v & 6) == 6 );
2035181254a7Smrg     assert( (6 & v) == 6 );
2036181254a7Smrg     assert( (v | 9) == 47 );
2037181254a7Smrg     assert( (9 | v) == 47 );
2038181254a7Smrg     assert( (v ^ 5) == 35 );
2039181254a7Smrg     assert( (5 ^ v) == 35 );
2040181254a7Smrg     assert( v << 1 == 76 );
2041181254a7Smrg     assert( Variant(1) << Variant(2) == 4 );
2042181254a7Smrg     assert( v >> 1 == 19 );
2043181254a7Smrg     assert( Variant(4) >> Variant(2) == 1 );
2044181254a7Smrg     assert( Variant("abc") ~ "def" == "abcdef" );
2045181254a7Smrg     assert( Variant("abc") ~ Variant("def") == "abcdef" );
2046181254a7Smrg 
2047181254a7Smrg     v = 38;
2048181254a7Smrg     v += 4;
2049181254a7Smrg     assert( v == 42 );
2050181254a7Smrg     v = 38; v -= 4; assert( v == 34 );
2051181254a7Smrg     v = 38; v *= 2; assert( v == 76 );
2052181254a7Smrg     v = 38; v /= 2; assert( v == 19 );
2053181254a7Smrg     v = 38; v %= 2; assert( v == 0 );
2054181254a7Smrg     v = 38; v &= 6; assert( v == 6 );
2055181254a7Smrg     v = 38; v |= 9; assert( v == 47 );
2056181254a7Smrg     v = 38; v ^= 5; assert( v == 35 );
2057181254a7Smrg     v = 38; v <<= 1; assert( v == 76 );
2058181254a7Smrg     v = 38; v >>= 1; assert( v == 19 );
2059181254a7Smrg     v = 38; v += 1;  assert( v < 40 );
2060181254a7Smrg 
2061181254a7Smrg     v = "abc";
2062181254a7Smrg     v ~= "def";
2063181254a7Smrg     assert( v == "abcdef", *v.peek!(char[]) );
2064181254a7Smrg     assert( Variant(0) < Variant(42) );
2065181254a7Smrg     assert( Variant(42) > Variant(0) );
2066181254a7Smrg     assert( Variant(42) > Variant(0.1) );
2067181254a7Smrg     assert( Variant(42.1) > Variant(1) );
2068181254a7Smrg     assert( Variant(21) == Variant(21) );
2069181254a7Smrg     assert( Variant(0) != Variant(42) );
2070181254a7Smrg     assert( Variant("bar") == Variant("bar") );
2071181254a7Smrg     assert( Variant("foo") != Variant("bar") );
2072181254a7Smrg 
2073181254a7Smrg     {
2074181254a7Smrg         auto v1 = Variant(42);
2075181254a7Smrg         auto v2 = Variant("foo");
2076181254a7Smrg 
2077181254a7Smrg         int[Variant] hash;
2078181254a7Smrg         hash[v1] = 0;
2079181254a7Smrg         hash[v2] = 1;
2080181254a7Smrg 
2081181254a7Smrg         assert( hash[v1] == 0 );
2082181254a7Smrg         assert( hash[v2] == 1 );
2083181254a7Smrg     }
2084181254a7Smrg 
2085181254a7Smrg     {
2086181254a7Smrg         int[char[]] hash;
2087181254a7Smrg         hash["a"] = 1;
2088181254a7Smrg         hash["b"] = 2;
2089181254a7Smrg         hash["c"] = 3;
2090181254a7Smrg         Variant vhash = hash;
2091181254a7Smrg 
2092181254a7Smrg         assert( vhash.get!(int[char[]])["a"] == 1 );
2093181254a7Smrg         assert( vhash.get!(int[char[]])["b"] == 2 );
2094181254a7Smrg         assert( vhash.get!(int[char[]])["c"] == 3 );
2095181254a7Smrg     }
2096181254a7Smrg }
2097181254a7Smrg 
2098181254a7Smrg @system unittest
2099181254a7Smrg {
2100181254a7Smrg     // check comparisons incompatible with AllowedTypes
2101181254a7Smrg     Algebraic!int v = 2;
2102181254a7Smrg 
2103181254a7Smrg     assert(v == 2);
2104181254a7Smrg     assert(v < 3);
2105*b1e83836Smrg     static assert(!__traits(compiles, () => v == long.max));
2106*b1e83836Smrg     static assert(!__traits(compiles, () => v == null));
2107*b1e83836Smrg     static assert(!__traits(compiles, () => v < long.max));
2108*b1e83836Smrg     static assert(!__traits(compiles, () => v > null));
2109181254a7Smrg }
2110181254a7Smrg 
2111*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=1558
2112181254a7Smrg @system unittest
2113181254a7Smrg {
2114181254a7Smrg     Variant va=1;
2115181254a7Smrg     Variant vb=-2;
2116181254a7Smrg     assert((va+vb).get!(int) == -1);
2117181254a7Smrg     assert((va-vb).get!(int) == 3);
2118181254a7Smrg }
2119181254a7Smrg 
2120181254a7Smrg @system unittest
2121181254a7Smrg {
2122181254a7Smrg     Variant a;
2123181254a7Smrg     a=5;
2124181254a7Smrg     Variant b;
2125181254a7Smrg     b=a;
2126181254a7Smrg     Variant[] c;
2127181254a7Smrg     c = variantArray(1, 2, 3.0, "hello", 4);
2128181254a7Smrg     assert(c[3] == "hello");
2129181254a7Smrg }
2130181254a7Smrg 
2131181254a7Smrg @system unittest
2132181254a7Smrg {
2133181254a7Smrg     Variant v = 5;
2134181254a7Smrg     assert(!__traits(compiles, v.coerce!(bool delegate())));
2135181254a7Smrg }
2136181254a7Smrg 
2137181254a7Smrg 
2138181254a7Smrg @system unittest
2139181254a7Smrg {
2140181254a7Smrg     struct Huge {
2141181254a7Smrg         real a, b, c, d, e, f, g;
2142181254a7Smrg     }
2143181254a7Smrg 
2144181254a7Smrg     Huge huge;
2145181254a7Smrg     huge.e = 42;
2146181254a7Smrg     Variant v;
2147181254a7Smrg     v = huge;  // Compile time error.
2148181254a7Smrg     assert(v.get!(Huge).e == 42);
2149181254a7Smrg }
2150181254a7Smrg 
2151181254a7Smrg @system unittest
2152181254a7Smrg {
2153181254a7Smrg     const x = Variant(42);
2154181254a7Smrg     auto y1 = x.get!(const int);
2155181254a7Smrg     // @@@BUG@@@
2156181254a7Smrg     //auto y2 = x.get!(immutable int)();
2157181254a7Smrg }
2158181254a7Smrg 
2159181254a7Smrg // test iteration
2160181254a7Smrg @system unittest
2161181254a7Smrg {
2162181254a7Smrg     auto v = Variant([ 1, 2, 3, 4 ][]);
2163181254a7Smrg     auto j = 0;
foreach(int i;v)2164181254a7Smrg     foreach (int i; v)
2165181254a7Smrg     {
2166181254a7Smrg         assert(i == ++j);
2167181254a7Smrg     }
2168181254a7Smrg     assert(j == 4);
2169181254a7Smrg }
2170181254a7Smrg 
2171181254a7Smrg // test convertibility
2172181254a7Smrg @system unittest
2173181254a7Smrg {
2174181254a7Smrg     auto v = Variant("abc".dup);
2175181254a7Smrg     assert(v.convertsTo!(char[]));
2176181254a7Smrg }
2177181254a7Smrg 
2178*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=5424
2179181254a7Smrg @system unittest
2180181254a7Smrg {
2181181254a7Smrg     interface A {
2182181254a7Smrg         void func1();
2183181254a7Smrg     }
2184181254a7Smrg     static class AC: A {
func1()2185181254a7Smrg         void func1() {
2186181254a7Smrg         }
2187181254a7Smrg     }
2188181254a7Smrg 
2189181254a7Smrg     A a = new AC();
2190181254a7Smrg     a.func1();
2191181254a7Smrg     Variant b = Variant(a);
2192181254a7Smrg }
2193181254a7Smrg 
2194*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=7070
2195181254a7Smrg @system unittest
2196181254a7Smrg {
2197181254a7Smrg     Variant v;
2198181254a7Smrg     v = null;
2199181254a7Smrg }
2200181254a7Smrg 
2201*b1e83836Smrg // Class and interface opEquals, https://issues.dlang.org/show_bug.cgi?id=12157
2202181254a7Smrg @system unittest
2203181254a7Smrg {
2204181254a7Smrg     class Foo { }
2205181254a7Smrg 
2206181254a7Smrg     class DerivedFoo : Foo { }
2207181254a7Smrg 
2208181254a7Smrg     Foo f1 = new Foo();
2209181254a7Smrg     Foo f2 = new DerivedFoo();
2210181254a7Smrg 
2211181254a7Smrg     Variant v1 = f1, v2 = f2;
2212181254a7Smrg     assert(v1 == f1);
2213181254a7Smrg     assert(v1 != new Foo());
2214181254a7Smrg     assert(v1 != f2);
2215181254a7Smrg     assert(v2 != v1);
2216181254a7Smrg     assert(v2 == f2);
2217181254a7Smrg }
2218181254a7Smrg 
2219*b1e83836Smrg // Const parameters with opCall, https://issues.dlang.org/show_bug.cgi?id=11361
2220181254a7Smrg @system unittest
2221181254a7Smrg {
t1(string c)2222181254a7Smrg     static string t1(string c) {
2223181254a7Smrg         return c ~ "a";
2224181254a7Smrg     }
2225181254a7Smrg 
t2(const (char)[]p)2226181254a7Smrg     static const(char)[] t2(const(char)[] p) {
2227181254a7Smrg         return p ~ "b";
2228181254a7Smrg     }
2229181254a7Smrg 
t3(int p)2230181254a7Smrg     static char[] t3(int p) {
2231181254a7Smrg         import std.conv : text;
2232181254a7Smrg         return p.text.dup;
2233181254a7Smrg     }
2234181254a7Smrg 
2235181254a7Smrg     Variant v1 = &t1;
2236181254a7Smrg     Variant v2 = &t2;
2237181254a7Smrg     Variant v3 = &t3;
2238181254a7Smrg 
2239181254a7Smrg     assert(v1("abc") == "abca");
2240181254a7Smrg     assert(v1("abc").type == typeid(string));
2241181254a7Smrg     assert(v2("abc") == "abcb");
2242181254a7Smrg 
2243181254a7Smrg     assert(v2(cast(char[])("abc".dup)) == "abcb");
2244181254a7Smrg     assert(v2("abc").type == typeid(const(char)[]));
2245181254a7Smrg 
2246181254a7Smrg     assert(v3(4) == ['4']);
2247181254a7Smrg     assert(v3(4).type == typeid(char[]));
2248181254a7Smrg }
2249181254a7Smrg 
2250*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=12071
2251181254a7Smrg @system unittest
2252181254a7Smrg {
2253181254a7Smrg     static struct Structure { int data; }
2254181254a7Smrg     alias VariantTest = Algebraic!(Structure delegate() pure nothrow @nogc @safe);
2255181254a7Smrg 
2256181254a7Smrg     bool called = false;
example()2257181254a7Smrg     Structure example() pure nothrow @nogc @safe
2258181254a7Smrg     {
2259181254a7Smrg         called = true;
2260181254a7Smrg         return Structure.init;
2261181254a7Smrg     }
2262181254a7Smrg     auto m = VariantTest(&example);
2263181254a7Smrg     m();
2264181254a7Smrg     assert(called);
2265181254a7Smrg }
2266181254a7Smrg 
2267*b1e83836Smrg // Ordering comparisons of incompatible types
2268*b1e83836Smrg // e.g. https://issues.dlang.org/show_bug.cgi?id=7990
2269181254a7Smrg @system unittest
2270181254a7Smrg {
2271181254a7Smrg     import std.exception : assertThrown;
2272181254a7Smrg     assertThrown!VariantException(Variant(3) < "a");
2273181254a7Smrg     assertThrown!VariantException("a" < Variant(3));
2274181254a7Smrg     assertThrown!VariantException(Variant(3) < Variant("a"));
2275181254a7Smrg 
2276181254a7Smrg     assertThrown!VariantException(Variant.init < Variant(3));
2277181254a7Smrg     assertThrown!VariantException(Variant(3) < Variant.init);
2278181254a7Smrg }
2279181254a7Smrg 
2280*b1e83836Smrg // Handling of unordered types
2281*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=9043
2282181254a7Smrg @system unittest
2283181254a7Smrg {
2284181254a7Smrg     import std.exception : assertThrown;
2285181254a7Smrg     static struct A { int a; }
2286181254a7Smrg 
2287181254a7Smrg     assert(Variant(A(3)) != A(4));
2288181254a7Smrg 
2289181254a7Smrg     assertThrown!VariantException(Variant(A(3)) < A(4));
2290181254a7Smrg     assertThrown!VariantException(A(3) < Variant(A(4)));
2291181254a7Smrg     assertThrown!VariantException(Variant(A(3)) < Variant(A(4)));
2292181254a7Smrg }
2293181254a7Smrg 
2294*b1e83836Smrg // Handling of empty types and arrays
2295*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=10958
2296181254a7Smrg @system unittest
2297181254a7Smrg {
2298181254a7Smrg     class EmptyClass { }
2299181254a7Smrg     struct EmptyStruct { }
2300181254a7Smrg     alias EmptyArray = void[0];
2301181254a7Smrg     alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray);
2302181254a7Smrg 
testEmpty(T)2303181254a7Smrg     Variant testEmpty(T)()
2304181254a7Smrg     {
2305181254a7Smrg         T inst;
2306181254a7Smrg         Variant v = inst;
2307181254a7Smrg         assert(v.get!T == inst);
2308181254a7Smrg         assert(v.peek!T !is null);
2309181254a7Smrg         assert(*v.peek!T == inst);
2310181254a7Smrg         Alg alg = inst;
2311181254a7Smrg         assert(alg.get!T == inst);
2312181254a7Smrg         return v;
2313181254a7Smrg     }
2314181254a7Smrg 
2315181254a7Smrg     testEmpty!EmptyClass();
2316181254a7Smrg     testEmpty!EmptyStruct();
2317181254a7Smrg     testEmpty!EmptyArray();
2318181254a7Smrg 
2319181254a7Smrg     // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0.
2320181254a7Smrg     EmptyArray arr = EmptyArray.init;
2321181254a7Smrg     Algebraic!(EmptyArray) a = arr;
2322181254a7Smrg     assert(a.length == 0);
2323181254a7Smrg     assert(a.get!EmptyArray == arr);
2324181254a7Smrg }
2325181254a7Smrg 
2326*b1e83836Smrg // Handling of void function pointers / delegates
2327*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=11360
2328181254a7Smrg @system unittest
2329181254a7Smrg {
t1()2330181254a7Smrg     static void t1() { }
2331181254a7Smrg     Variant v = &t1;
2332181254a7Smrg     assert(v() == Variant.init);
2333181254a7Smrg 
t2()2334181254a7Smrg     static int t2() { return 3; }
2335181254a7Smrg     Variant v2 = &t2;
2336181254a7Smrg     assert(v2() == 3);
2337181254a7Smrg }
2338181254a7Smrg 
2339*b1e83836Smrg // Using peek for large structs
2340*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=8580
2341181254a7Smrg @system unittest
2342181254a7Smrg {
TestStruct(bool pad)2343181254a7Smrg     struct TestStruct(bool pad)
2344181254a7Smrg     {
2345181254a7Smrg         int val1;
2346181254a7Smrg         static if (pad)
2347181254a7Smrg             ubyte[Variant.size] padding;
2348181254a7Smrg         int val2;
2349181254a7Smrg     }
2350181254a7Smrg 
testPeekWith(T)2351181254a7Smrg     void testPeekWith(T)()
2352181254a7Smrg     {
2353181254a7Smrg         T inst;
2354181254a7Smrg         inst.val1 = 3;
2355181254a7Smrg         inst.val2 = 4;
2356181254a7Smrg         Variant v = inst;
2357181254a7Smrg         T* original = v.peek!T;
2358181254a7Smrg         assert(original.val1 == 3);
2359181254a7Smrg         assert(original.val2 == 4);
2360181254a7Smrg         original.val1 = 6;
2361181254a7Smrg         original.val2 = 8;
2362181254a7Smrg         T modified = v.get!T;
2363181254a7Smrg         assert(modified.val1 == 6);
2364181254a7Smrg         assert(modified.val2 == 8);
2365181254a7Smrg     }
2366181254a7Smrg 
2367181254a7Smrg     testPeekWith!(TestStruct!false)();
2368181254a7Smrg     testPeekWith!(TestStruct!true)();
2369181254a7Smrg }
2370181254a7Smrg 
2371*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=18780
2372*b1e83836Smrg @system unittest
2373*b1e83836Smrg {
2374*b1e83836Smrg     int x = 7;
2375*b1e83836Smrg     Variant a = x;
2376*b1e83836Smrg     assert(a.convertsTo!ulong);
2377*b1e83836Smrg     assert(a.convertsTo!uint);
2378*b1e83836Smrg }
2379*b1e83836Smrg 
2380181254a7Smrg /**
2381181254a7Smrg  * Applies a delegate or function to the given $(LREF Algebraic) depending on the held type,
2382181254a7Smrg  * ensuring that all types are handled by the visiting functions.
2383181254a7Smrg  *
2384181254a7Smrg  * The delegate or function having the currently held value as parameter is called
2385*b1e83836Smrg  * with `variant`'s current value. Visiting handlers are passed
2386181254a7Smrg  * in the template parameter list.
2387181254a7Smrg  * It is statically ensured that all held types of
2388*b1e83836Smrg  * `variant` are handled across all handlers.
2389*b1e83836Smrg  * `visit` allows delegates and static functions to be passed
2390181254a7Smrg  * as parameters.
2391181254a7Smrg  *
2392181254a7Smrg  * If a function with an untyped parameter is specified, this function is called
2393181254a7Smrg  * when the variant contains a type that does not match any other function.
2394181254a7Smrg  * This can be used to apply the same function across multiple possible types.
2395181254a7Smrg  * Exactly one generic function is allowed.
2396181254a7Smrg  *
2397181254a7Smrg  * If a function without parameters is specified, this function is called
2398181254a7Smrg  * when `variant` doesn't hold a value. Exactly one parameter-less function
2399181254a7Smrg  * is allowed.
2400181254a7Smrg  *
2401181254a7Smrg  * Duplicate overloads matching the same type in one of the visitors are disallowed.
2402181254a7Smrg  *
2403181254a7Smrg  * Returns: The return type of visit is deduced from the visiting functions and must be
2404181254a7Smrg  * the same across all overloads.
2405181254a7Smrg  * Throws: $(LREF VariantException) if `variant` doesn't hold a value and no
2406181254a7Smrg  * parameter-less fallback function is specified.
2407181254a7Smrg  */
2408181254a7Smrg template visit(Handlers...)
2409181254a7Smrg if (Handlers.length > 0)
2410181254a7Smrg {
2411181254a7Smrg     ///
2412181254a7Smrg     auto visit(VariantType)(VariantType variant)
2413181254a7Smrg         if (isAlgebraic!VariantType)
2414181254a7Smrg     {
2415181254a7Smrg         return visitImpl!(true, VariantType, Handlers)(variant);
2416181254a7Smrg     }
2417181254a7Smrg }
2418181254a7Smrg 
2419181254a7Smrg ///
2420181254a7Smrg @system unittest
2421181254a7Smrg {
2422181254a7Smrg     Algebraic!(int, string) variant;
2423181254a7Smrg 
2424181254a7Smrg     variant = 10;
2425181254a7Smrg     assert(variant.visit!((string s) => cast(int) s.length,
2426181254a7Smrg                           (int i)    => i)()
2427181254a7Smrg                           == 10);
2428181254a7Smrg     variant = "string";
2429181254a7Smrg     assert(variant.visit!((int i) => i,
2430181254a7Smrg                           (string s) => cast(int) s.length)()
2431181254a7Smrg                           == 6);
2432181254a7Smrg 
2433181254a7Smrg     // Error function usage
2434181254a7Smrg     Algebraic!(int, string) emptyVar;
2435181254a7Smrg     auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
2436181254a7Smrg                           (int i)    => i,
2437181254a7Smrg                           () => -1)();
2438181254a7Smrg     assert(rslt == -1);
2439181254a7Smrg 
2440181254a7Smrg     // Generic function usage
2441181254a7Smrg     Algebraic!(int, float, real) number = 2;
2442181254a7Smrg     assert(number.visit!(x => x += 1) == 3);
2443181254a7Smrg 
2444181254a7Smrg     // Generic function for int/float with separate behavior for string
2445181254a7Smrg     Algebraic!(int, float, string) something = 2;
2446181254a7Smrg     assert(something.visit!((string s) => s.length, x => x) == 2); // generic
2447181254a7Smrg     something = "asdf";
2448181254a7Smrg     assert(something.visit!((string s) => s.length, x => x) == 4); // string
2449181254a7Smrg 
2450181254a7Smrg     // Generic handler and empty handler
2451181254a7Smrg     Algebraic!(int, float, real) empty2;
2452181254a7Smrg     assert(empty2.visit!(x => x + 1, () => -1) == -1);
2453181254a7Smrg }
2454181254a7Smrg 
2455181254a7Smrg @system unittest
2456181254a7Smrg {
2457181254a7Smrg     Algebraic!(size_t, string) variant;
2458181254a7Smrg 
2459181254a7Smrg     // not all handled check
2460181254a7Smrg     static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
2461181254a7Smrg 
2462181254a7Smrg     variant = cast(size_t) 10;
2463181254a7Smrg     auto which = 0;
2464181254a7Smrg     variant.visit!( (string s) => which = 1,
2465181254a7Smrg                     (size_t i) => which = 0
2466181254a7Smrg                     )();
2467181254a7Smrg 
2468181254a7Smrg     // integer overload was called
2469181254a7Smrg     assert(which == 0);
2470181254a7Smrg 
2471181254a7Smrg     // mustn't compile as generic Variant not supported
2472181254a7Smrg     Variant v;
2473181254a7Smrg     static assert(!__traits(compiles, v.visit!((string s) => which = 1,
2474181254a7Smrg                                                (size_t i) => which = 0
2475181254a7Smrg                                                 )()
2476181254a7Smrg                                                 ));
2477181254a7Smrg 
func(string s)2478181254a7Smrg     static size_t func(string s) {
2479181254a7Smrg         return s.length;
2480181254a7Smrg     }
2481181254a7Smrg 
2482181254a7Smrg     variant = "test";
2483181254a7Smrg     assert( 4 == variant.visit!(func,
2484181254a7Smrg                                 (size_t i) => i
2485181254a7Smrg                                 )());
2486181254a7Smrg 
2487181254a7Smrg     Algebraic!(int, float, string) variant2 = 5.0f;
2488181254a7Smrg     // Shouldn' t compile as float not handled by visitor.
2489181254a7Smrg     static assert(!__traits(compiles, variant2.visit!(
2490181254a7Smrg                         (int _) {},
2491181254a7Smrg                         (string _) {})()));
2492181254a7Smrg 
2493181254a7Smrg     Algebraic!(size_t, string, float) variant3;
2494181254a7Smrg     variant3 = 10.0f;
2495181254a7Smrg     auto floatVisited = false;
2496181254a7Smrg 
2497181254a7Smrg     assert(variant3.visit!(
2498181254a7Smrg                  (float f) { floatVisited = true; return cast(size_t) f; },
2499181254a7Smrg                  func,
2500181254a7Smrg                  (size_t i) { return i; }
2501181254a7Smrg                  )() == 10);
2502181254a7Smrg     assert(floatVisited == true);
2503181254a7Smrg 
2504181254a7Smrg     Algebraic!(float, string) variant4;
2505181254a7Smrg 
2506181254a7Smrg     assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
2507181254a7Smrg 
2508181254a7Smrg     // double error func check
2509181254a7Smrg     static assert(!__traits(compiles,
2510181254a7Smrg                             visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
2511181254a7Smrg                  );
2512181254a7Smrg }
2513181254a7Smrg 
2514181254a7Smrg // disallow providing multiple generic handlers to visit
2515181254a7Smrg // disallow a generic handler that does not apply to all types
2516181254a7Smrg @system unittest
2517181254a7Smrg {
2518181254a7Smrg     Algebraic!(int, float) number = 2;
2519181254a7Smrg     // ok, x + 1 valid for int and float
2520181254a7Smrg     static assert( __traits(compiles, number.visit!(x => x + 1)));
2521181254a7Smrg     // bad, two generic handlers
2522181254a7Smrg     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
2523181254a7Smrg     // bad, x ~ "a" does not apply to int or float
2524181254a7Smrg     static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2525181254a7Smrg     // bad, x ~ "a" does not apply to int or float
2526181254a7Smrg     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2527181254a7Smrg 
2528181254a7Smrg     Algebraic!(int, string) maybenumber = 2;
2529181254a7Smrg     // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
2530*b1e83836Smrg     static assert( __traits(compiles, maybenumber.visit!((string x) => x ~ "a", x => "foobar"[0 .. x + 1])));
2531181254a7Smrg     // bad, x ~ "a" valid for string but not int
2532*b1e83836Smrg     static assert(!__traits(compiles, maybenumber.visit!(x => x ~ "a")));
2533181254a7Smrg     // bad, two generics, each only applies in one case
2534*b1e83836Smrg     static assert(!__traits(compiles, maybenumber.visit!(x => x + 1, x => x ~ "a")));
2535181254a7Smrg }
2536181254a7Smrg 
2537181254a7Smrg /**
2538181254a7Smrg  * Behaves as $(LREF visit) but doesn't enforce that all types are handled
2539181254a7Smrg  * by the visiting functions.
2540181254a7Smrg  *
2541181254a7Smrg  * If a parameter-less function is specified it is called when
2542*b1e83836Smrg  * either `variant` doesn't hold a value or holds a type
2543181254a7Smrg  * which isn't handled by the visiting functions.
2544181254a7Smrg  *
2545181254a7Smrg  * Returns: The return type of tryVisit is deduced from the visiting functions and must be
2546181254a7Smrg  * the same across all overloads.
2547181254a7Smrg  * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
2548181254a7Smrg  * `variant` holds a value which isn't handled by the visiting functions,
2549181254a7Smrg  * when no parameter-less fallback function is specified.
2550181254a7Smrg  */
2551181254a7Smrg template tryVisit(Handlers...)
2552181254a7Smrg if (Handlers.length > 0)
2553181254a7Smrg {
2554181254a7Smrg     ///
2555181254a7Smrg     auto tryVisit(VariantType)(VariantType variant)
2556181254a7Smrg         if (isAlgebraic!VariantType)
2557181254a7Smrg     {
2558181254a7Smrg         return visitImpl!(false, VariantType, Handlers)(variant);
2559181254a7Smrg     }
2560181254a7Smrg }
2561181254a7Smrg 
2562181254a7Smrg ///
2563181254a7Smrg @system unittest
2564181254a7Smrg {
2565181254a7Smrg     Algebraic!(int, string) variant;
2566181254a7Smrg 
2567181254a7Smrg     variant = 10;
2568181254a7Smrg     auto which = -1;
2569181254a7Smrg     variant.tryVisit!((int i) { which = 0; })();
2570181254a7Smrg     assert(which == 0);
2571181254a7Smrg 
2572181254a7Smrg     // Error function usage
2573181254a7Smrg     variant = "test";
2574181254a7Smrg     variant.tryVisit!((int i) { which = 0; },
2575181254a7Smrg                       ()      { which = -100; })();
2576181254a7Smrg     assert(which == -100);
2577181254a7Smrg }
2578181254a7Smrg 
2579181254a7Smrg @system unittest
2580181254a7Smrg {
2581181254a7Smrg     import std.exception : assertThrown;
2582181254a7Smrg     Algebraic!(int, string) variant;
2583181254a7Smrg 
2584181254a7Smrg     variant = 10;
2585181254a7Smrg     auto which = -1;
2586181254a7Smrg     variant.tryVisit!((int i){ which = 0; })();
2587181254a7Smrg 
2588181254a7Smrg     assert(which == 0);
2589181254a7Smrg 
2590181254a7Smrg     variant = "test";
2591181254a7Smrg 
2592181254a7Smrg     assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
2593181254a7Smrg 
errorfunc()2594181254a7Smrg     void errorfunc()
2595181254a7Smrg     {
2596181254a7Smrg         which = -1;
2597181254a7Smrg     }
2598181254a7Smrg 
2599181254a7Smrg     variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2600181254a7Smrg 
2601181254a7Smrg     assert(which == -1);
2602181254a7Smrg }
2603181254a7Smrg 
isAlgebraic(Type)2604181254a7Smrg private template isAlgebraic(Type)
2605181254a7Smrg {
2606181254a7Smrg     static if (is(Type _ == VariantN!T, T...))
2607181254a7Smrg         enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
2608181254a7Smrg     else
2609181254a7Smrg         enum isAlgebraic = false;
2610181254a7Smrg }
2611181254a7Smrg 
2612181254a7Smrg @system unittest
2613181254a7Smrg {
2614181254a7Smrg     static assert(!isAlgebraic!(Variant));
2615181254a7Smrg     static assert( isAlgebraic!(Algebraic!(string)));
2616181254a7Smrg     static assert( isAlgebraic!(Algebraic!(int, int[])));
2617181254a7Smrg }
2618181254a7Smrg 
2619181254a7Smrg private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2620181254a7Smrg if (isAlgebraic!VariantType && Handler.length > 0)
2621181254a7Smrg {
2622181254a7Smrg     alias AllowedTypes = VariantType.AllowedTypes;
2623181254a7Smrg 
2624181254a7Smrg 
2625181254a7Smrg     /**
2626*b1e83836Smrg      * Returns: Struct where `indices`  is an array which
2627181254a7Smrg      * contains at the n-th position the index in Handler which takes the
2628181254a7Smrg      * n-th type of AllowedTypes. If an Handler doesn't match an
2629181254a7Smrg      * AllowedType, -1 is set. If a function in the delegates doesn't
2630*b1e83836Smrg      * have parameters, the field `exceptionFuncIdx` is set;
2631181254a7Smrg      * otherwise it's -1.
2632181254a7Smrg      */
visitGetOverloadMap()2633181254a7Smrg     auto visitGetOverloadMap()
2634181254a7Smrg     {
2635181254a7Smrg         struct Result {
2636181254a7Smrg             int[AllowedTypes.length] indices;
2637181254a7Smrg             int exceptionFuncIdx = -1;
2638181254a7Smrg             int generalFuncIdx = -1;
2639181254a7Smrg         }
2640181254a7Smrg 
2641181254a7Smrg         Result result;
2642181254a7Smrg 
2643*b1e83836Smrg         enum int nonmatch = ()
2644*b1e83836Smrg         {
2645*b1e83836Smrg             foreach (int dgidx, dg; Handler)
2646*b1e83836Smrg             {
2647*b1e83836Smrg                 bool found = false;
2648*b1e83836Smrg                 foreach (T; AllowedTypes)
2649*b1e83836Smrg                 {
2650*b1e83836Smrg                     found |= __traits(compiles, { static assert(isSomeFunction!(dg!T)); });
2651*b1e83836Smrg                     found |= __traits(compiles, (T t) { dg(t); });
2652*b1e83836Smrg                     found |= __traits(compiles, dg());
2653*b1e83836Smrg                 }
2654*b1e83836Smrg                 if (!found) return dgidx;
2655*b1e83836Smrg             }
2656*b1e83836Smrg             return -1;
2657*b1e83836Smrg         }();
2658*b1e83836Smrg         static assert(nonmatch == -1, "No match for visit handler #"~
2659*b1e83836Smrg             nonmatch.stringof~" ("~Handler[nonmatch].stringof~")");
2660*b1e83836Smrg 
2661181254a7Smrg         foreach (tidx, T; AllowedTypes)
2662181254a7Smrg         {
2663181254a7Smrg             bool added = false;
2664181254a7Smrg             foreach (dgidx, dg; Handler)
2665181254a7Smrg             {
2666181254a7Smrg                 // Handle normal function objects
2667181254a7Smrg                 static if (isSomeFunction!dg)
2668181254a7Smrg                 {
2669181254a7Smrg                     alias Params = Parameters!dg;
2670181254a7Smrg                     static if (Params.length == 0)
2671181254a7Smrg                     {
2672181254a7Smrg                         // Just check exception functions in the first
2673181254a7Smrg                         // inner iteration (over delegates)
2674181254a7Smrg                         if (tidx > 0)
2675181254a7Smrg                             continue;
2676181254a7Smrg                         else
2677181254a7Smrg                         {
2678181254a7Smrg                             if (result.exceptionFuncIdx != -1)
2679181254a7Smrg                                 assert(false, "duplicate parameter-less (error-)function specified");
2680181254a7Smrg                             result.exceptionFuncIdx = dgidx;
2681181254a7Smrg                         }
2682181254a7Smrg                     }
2683181254a7Smrg                     else static if (is(Params[0] == T) || is(Unqual!(Params[0]) == T))
2684181254a7Smrg                     {
2685181254a7Smrg                         if (added)
2686181254a7Smrg                             assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'");
2687181254a7Smrg 
2688181254a7Smrg                         added = true;
2689181254a7Smrg                         result.indices[tidx] = dgidx;
2690181254a7Smrg                     }
2691181254a7Smrg                 }
2692*b1e83836Smrg                 else static if (__traits(compiles, { static assert(isSomeFunction!(dg!T)); }))
2693181254a7Smrg                 {
2694181254a7Smrg                     assert(result.generalFuncIdx == -1 ||
2695181254a7Smrg                            result.generalFuncIdx == dgidx,
2696181254a7Smrg                            "Only one generic visitor function is allowed");
2697181254a7Smrg                     result.generalFuncIdx = dgidx;
2698181254a7Smrg                 }
2699181254a7Smrg                 // Handle composite visitors with opCall overloads
2700181254a7Smrg             }
2701181254a7Smrg 
2702181254a7Smrg             if (!added)
2703181254a7Smrg                 result.indices[tidx] = -1;
2704181254a7Smrg         }
2705181254a7Smrg 
2706181254a7Smrg         return result;
2707181254a7Smrg     }
2708181254a7Smrg 
2709181254a7Smrg     enum HandlerOverloadMap = visitGetOverloadMap();
2710181254a7Smrg 
2711181254a7Smrg     if (!variant.hasValue)
2712181254a7Smrg     {
2713181254a7Smrg         // Call the exception function. The HandlerOverloadMap
2714181254a7Smrg         // will have its exceptionFuncIdx field set to value != -1 if an
2715181254a7Smrg         // exception function has been specified; otherwise we just through an exception.
2716181254a7Smrg         static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2717181254a7Smrg             return Handler[ HandlerOverloadMap.exceptionFuncIdx ]();
2718181254a7Smrg         else
2719181254a7Smrg             throw new VariantException("variant must hold a value before being visited.");
2720181254a7Smrg     }
2721181254a7Smrg 
foreach(idx,T;AllowedTypes)2722181254a7Smrg     foreach (idx, T; AllowedTypes)
2723181254a7Smrg     {
2724181254a7Smrg         if (auto ptr = variant.peek!T)
2725181254a7Smrg         {
2726181254a7Smrg             enum dgIdx = HandlerOverloadMap.indices[idx];
2727181254a7Smrg 
2728181254a7Smrg             static if (dgIdx == -1)
2729181254a7Smrg             {
2730181254a7Smrg                 static if (HandlerOverloadMap.generalFuncIdx >= 0)
2731181254a7Smrg                     return Handler[HandlerOverloadMap.generalFuncIdx](*ptr);
2732181254a7Smrg                 else static if (Strict)
2733181254a7Smrg                     static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified");
2734181254a7Smrg                 else static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2735181254a7Smrg                     return Handler[HandlerOverloadMap.exceptionFuncIdx]();
2736181254a7Smrg                 else
2737181254a7Smrg                     throw new VariantException(
2738181254a7Smrg                         "variant holds value of type '"
2739181254a7Smrg                         ~ T.stringof ~
2740181254a7Smrg                         "' but no visitor has been provided"
2741181254a7Smrg                     );
2742181254a7Smrg             }
2743181254a7Smrg             else
2744181254a7Smrg             {
2745181254a7Smrg                 return Handler[ dgIdx ](*ptr);
2746181254a7Smrg             }
2747181254a7Smrg         }
2748181254a7Smrg     }
2749181254a7Smrg 
2750181254a7Smrg     assert(false);
2751181254a7Smrg }
2752181254a7Smrg 
2753*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=21253
2754*b1e83836Smrg @system unittest
2755*b1e83836Smrg {
2756*b1e83836Smrg     static struct A { int n; }
2757*b1e83836Smrg     static struct B {        }
2758*b1e83836Smrg 
2759*b1e83836Smrg     auto a = Algebraic!(A, B)(B());
2760*b1e83836Smrg     assert(a.visit!(
2761*b1e83836Smrg         (B _) => 42,
2762*b1e83836Smrg         (a  ) => a.n
2763*b1e83836Smrg     ) == 42);
2764*b1e83836Smrg }
2765*b1e83836Smrg 
2766181254a7Smrg @system unittest
2767181254a7Smrg {
2768181254a7Smrg     // validate that visit can be called with a const type
2769181254a7Smrg     struct Foo { int depth; }
2770181254a7Smrg     struct Bar { int depth; }
2771181254a7Smrg     alias FooBar = Algebraic!(Foo, Bar);
2772181254a7Smrg 
depth(in FooBar fb)2773181254a7Smrg     int depth(in FooBar fb) {
2774181254a7Smrg         return fb.visit!((Foo foo) => foo.depth,
2775181254a7Smrg                          (Bar bar) => bar.depth);
2776181254a7Smrg     }
2777181254a7Smrg 
2778181254a7Smrg     FooBar fb = Foo(3);
2779181254a7Smrg     assert(depth(fb) == 3);
2780181254a7Smrg }
2781181254a7Smrg 
2782*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=16383
2783181254a7Smrg @system unittest
2784181254a7Smrg {
this()2785181254a7Smrg     class Foo {this() immutable {}}
2786181254a7Smrg     alias V = Algebraic!(immutable Foo);
2787181254a7Smrg 
2788181254a7Smrg     auto x = V(new immutable Foo).visit!(
2789181254a7Smrg         (immutable(Foo) _) => 3
2790181254a7Smrg     );
2791181254a7Smrg     assert(x == 3);
2792181254a7Smrg }
2793181254a7Smrg 
2794*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=5310
2795181254a7Smrg @system unittest
2796181254a7Smrg {
2797181254a7Smrg     const Variant a;
2798181254a7Smrg     assert(a == a);
2799181254a7Smrg     Variant b;
2800181254a7Smrg     assert(a == b);
2801181254a7Smrg     assert(b == a);
2802181254a7Smrg }
2803181254a7Smrg 
2804181254a7Smrg @system unittest
2805181254a7Smrg {
2806181254a7Smrg     const Variant a = [2];
2807181254a7Smrg     assert(a[0] == 2);
2808181254a7Smrg }
2809181254a7Smrg 
2810*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=10017
2811181254a7Smrg @system unittest
2812181254a7Smrg {
2813181254a7Smrg     static struct S
2814181254a7Smrg     {
2815181254a7Smrg         ubyte[Variant.size + 1] s;
2816181254a7Smrg     }
2817181254a7Smrg 
2818181254a7Smrg     Variant v1, v2;
2819181254a7Smrg     v1 = S(); // the payload is allocated on the heap
2820181254a7Smrg     v2 = v1;  // AssertError: target must be non-null
2821181254a7Smrg     assert(v1 == v2);
2822181254a7Smrg }
2823*b1e83836Smrg 
2824*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=7069
2825181254a7Smrg @system unittest
2826181254a7Smrg {
2827181254a7Smrg     import std.exception : assertThrown;
2828181254a7Smrg     Variant v;
2829181254a7Smrg 
2830181254a7Smrg     int i = 10;
2831181254a7Smrg     v = i;
2832*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ConstOf))
2833181254a7Smrg     {
2834181254a7Smrg         assert(v.get!(qual!int) == 10);
2835181254a7Smrg         assert(v.get!(qual!float) == 10.0f);
2836181254a7Smrg     }
2837*b1e83836Smrg     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2838181254a7Smrg     {
2839181254a7Smrg         assertThrown!VariantException(v.get!(qual!int));
2840181254a7Smrg     }
2841181254a7Smrg 
2842181254a7Smrg     const(int) ci = 20;
2843181254a7Smrg     v = ci;
2844*b1e83836Smrg     static foreach (qual; AliasSeq!(ConstOf))
2845181254a7Smrg     {
2846181254a7Smrg         assert(v.get!(qual!int) == 20);
2847181254a7Smrg         assert(v.get!(qual!float) == 20.0f);
2848181254a7Smrg     }
2849*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2850181254a7Smrg     {
2851181254a7Smrg         assertThrown!VariantException(v.get!(qual!int));
2852181254a7Smrg         assertThrown!VariantException(v.get!(qual!float));
2853181254a7Smrg     }
2854181254a7Smrg 
2855181254a7Smrg     immutable(int) ii = ci;
2856181254a7Smrg     v = ii;
2857*b1e83836Smrg     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2858181254a7Smrg     {
2859181254a7Smrg         assert(v.get!(qual!int) == 20);
2860181254a7Smrg         assert(v.get!(qual!float) == 20.0f);
2861181254a7Smrg     }
2862*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, SharedOf))
2863181254a7Smrg     {
2864181254a7Smrg         assertThrown!VariantException(v.get!(qual!int));
2865181254a7Smrg         assertThrown!VariantException(v.get!(qual!float));
2866181254a7Smrg     }
2867181254a7Smrg 
2868181254a7Smrg     int[] ai = [1,2,3];
2869181254a7Smrg     v = ai;
2870*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ConstOf))
2871181254a7Smrg     {
2872181254a7Smrg         assert(v.get!(qual!(int[])) == [1,2,3]);
2873181254a7Smrg         assert(v.get!(qual!(int)[]) == [1,2,3]);
2874181254a7Smrg     }
2875*b1e83836Smrg     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2876181254a7Smrg     {
2877181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2878181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2879181254a7Smrg     }
2880181254a7Smrg 
2881181254a7Smrg     const(int[]) cai = [4,5,6];
2882181254a7Smrg     v = cai;
2883*b1e83836Smrg     static foreach (qual; AliasSeq!(ConstOf))
2884181254a7Smrg     {
2885181254a7Smrg         assert(v.get!(qual!(int[])) == [4,5,6]);
2886181254a7Smrg         assert(v.get!(qual!(int)[]) == [4,5,6]);
2887181254a7Smrg     }
2888*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2889181254a7Smrg     {
2890181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2891181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2892181254a7Smrg     }
2893181254a7Smrg 
2894181254a7Smrg     immutable(int[]) iai = [7,8,9];
2895181254a7Smrg     v = iai;
2896181254a7Smrg     //assert(v.get!(immutable(int[])) == [7,8,9]);   // Bug ??? runtime error
2897181254a7Smrg     assert(v.get!(immutable(int)[]) == [7,8,9]);
2898181254a7Smrg     assert(v.get!(const(int[])) == [7,8,9]);
2899181254a7Smrg     assert(v.get!(const(int)[]) == [7,8,9]);
2900181254a7Smrg     //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2901181254a7Smrg     //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2902*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias))
2903181254a7Smrg     {
2904181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2905181254a7Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2906181254a7Smrg     }
2907181254a7Smrg 
2908181254a7Smrg     class A {}
2909181254a7Smrg     class B : A {}
2910181254a7Smrg     B b = new B();
2911181254a7Smrg     v = b;
2912*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ConstOf))
2913181254a7Smrg     {
2914181254a7Smrg         assert(v.get!(qual!B) is b);
2915181254a7Smrg         assert(v.get!(qual!A) is b);
2916181254a7Smrg         assert(v.get!(qual!Object) is b);
2917181254a7Smrg     }
2918*b1e83836Smrg     static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2919181254a7Smrg     {
2920181254a7Smrg         assertThrown!VariantException(v.get!(qual!B));
2921181254a7Smrg         assertThrown!VariantException(v.get!(qual!A));
2922181254a7Smrg         assertThrown!VariantException(v.get!(qual!Object));
2923181254a7Smrg     }
2924181254a7Smrg 
2925181254a7Smrg     const(B) cb = new B();
2926181254a7Smrg     v = cb;
2927*b1e83836Smrg     static foreach (qual; AliasSeq!(ConstOf))
2928181254a7Smrg     {
2929181254a7Smrg         assert(v.get!(qual!B) is cb);
2930181254a7Smrg         assert(v.get!(qual!A) is cb);
2931181254a7Smrg         assert(v.get!(qual!Object) is cb);
2932181254a7Smrg     }
2933*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2934181254a7Smrg     {
2935181254a7Smrg         assertThrown!VariantException(v.get!(qual!B));
2936181254a7Smrg         assertThrown!VariantException(v.get!(qual!A));
2937181254a7Smrg         assertThrown!VariantException(v.get!(qual!Object));
2938181254a7Smrg     }
2939181254a7Smrg 
2940181254a7Smrg     immutable(B) ib = new immutable(B)();
2941181254a7Smrg     v = ib;
2942*b1e83836Smrg     static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2943181254a7Smrg     {
2944181254a7Smrg         assert(v.get!(qual!B) is ib);
2945181254a7Smrg         assert(v.get!(qual!A) is ib);
2946181254a7Smrg         assert(v.get!(qual!Object) is ib);
2947181254a7Smrg     }
2948*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, SharedOf))
2949181254a7Smrg     {
2950181254a7Smrg         assertThrown!VariantException(v.get!(qual!B));
2951181254a7Smrg         assertThrown!VariantException(v.get!(qual!A));
2952181254a7Smrg         assertThrown!VariantException(v.get!(qual!Object));
2953181254a7Smrg     }
2954181254a7Smrg 
2955181254a7Smrg     shared(B) sb = new shared B();
2956181254a7Smrg     v = sb;
2957*b1e83836Smrg     static foreach (qual; AliasSeq!(SharedOf, SharedConstOf))
2958181254a7Smrg     {
2959181254a7Smrg         assert(v.get!(qual!B) is sb);
2960181254a7Smrg         assert(v.get!(qual!A) is sb);
2961181254a7Smrg         assert(v.get!(qual!Object) is sb);
2962181254a7Smrg     }
2963*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ImmutableOf, ConstOf))
2964181254a7Smrg     {
2965181254a7Smrg         assertThrown!VariantException(v.get!(qual!B));
2966181254a7Smrg         assertThrown!VariantException(v.get!(qual!A));
2967181254a7Smrg         assertThrown!VariantException(v.get!(qual!Object));
2968181254a7Smrg     }
2969181254a7Smrg 
2970181254a7Smrg     shared(const(B)) scb = new shared const B();
2971181254a7Smrg     v = scb;
2972*b1e83836Smrg     static foreach (qual; AliasSeq!(SharedConstOf))
2973181254a7Smrg     {
2974181254a7Smrg         assert(v.get!(qual!B) is scb);
2975181254a7Smrg         assert(v.get!(qual!A) is scb);
2976181254a7Smrg         assert(v.get!(qual!Object) is scb);
2977181254a7Smrg     }
2978*b1e83836Smrg     static foreach (qual; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf))
2979181254a7Smrg     {
2980181254a7Smrg         assertThrown!VariantException(v.get!(qual!B));
2981181254a7Smrg         assertThrown!VariantException(v.get!(qual!A));
2982181254a7Smrg         assertThrown!VariantException(v.get!(qual!Object));
2983181254a7Smrg     }
2984181254a7Smrg }
2985181254a7Smrg 
2986*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=12540
2987181254a7Smrg @system unittest
2988181254a7Smrg {
2989181254a7Smrg     static struct DummyScope
2990181254a7Smrg     {
2991181254a7Smrg         alias Alias12540 = Algebraic!Class12540;
2992181254a7Smrg 
2993181254a7Smrg         static class Class12540
2994181254a7Smrg         {
2995181254a7Smrg             Alias12540 entity;
2996181254a7Smrg         }
2997181254a7Smrg     }
2998181254a7Smrg }
2999181254a7Smrg 
3000181254a7Smrg @system unittest
3001181254a7Smrg {
3002181254a7Smrg     // https://issues.dlang.org/show_bug.cgi?id=10194
3003181254a7Smrg     // Also test for elaborate copying
3004181254a7Smrg     static struct S
3005181254a7Smrg     {
3006181254a7Smrg         @disable this();
3007181254a7Smrg         this(int dummy)
3008181254a7Smrg         {
3009181254a7Smrg             ++cnt;
3010181254a7Smrg         }
3011181254a7Smrg 
3012181254a7Smrg         this(this)
3013181254a7Smrg         {
3014181254a7Smrg             ++cnt;
3015181254a7Smrg         }
3016181254a7Smrg 
3017181254a7Smrg         @disable S opAssign();
3018181254a7Smrg 
3019181254a7Smrg         ~this()
3020181254a7Smrg         {
3021181254a7Smrg             --cnt;
3022181254a7Smrg             assert(cnt >= 0);
3023181254a7Smrg         }
3024181254a7Smrg         static int cnt = 0;
3025181254a7Smrg     }
3026181254a7Smrg 
3027181254a7Smrg     {
3028181254a7Smrg         Variant v;
3029181254a7Smrg         {
3030181254a7Smrg             v = S(0);
3031181254a7Smrg             assert(S.cnt == 1);
3032181254a7Smrg         }
3033181254a7Smrg         assert(S.cnt == 1);
3034181254a7Smrg 
3035181254a7Smrg         // assigning a new value should destroy the existing one
3036181254a7Smrg         v = 0;
3037181254a7Smrg         assert(S.cnt == 0);
3038181254a7Smrg 
3039181254a7Smrg         // destroying the variant should destroy it's current value
3040181254a7Smrg         v = S(0);
3041181254a7Smrg         assert(S.cnt == 1);
3042181254a7Smrg     }
3043181254a7Smrg     assert(S.cnt == 0);
3044181254a7Smrg }
3045181254a7Smrg 
3046181254a7Smrg @system unittest
3047181254a7Smrg {
3048*b1e83836Smrg     // https://issues.dlang.org/show_bug.cgi?id=13300
3049181254a7Smrg     static struct S
3050181254a7Smrg     {
3051181254a7Smrg         this(this) {}
3052181254a7Smrg         ~this() {}
3053181254a7Smrg     }
3054181254a7Smrg 
3055181254a7Smrg     static assert( hasElaborateCopyConstructor!(Variant));
3056181254a7Smrg     static assert(!hasElaborateCopyConstructor!(Algebraic!bool));
3057181254a7Smrg     static assert( hasElaborateCopyConstructor!(Algebraic!S));
3058181254a7Smrg     static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S)));
3059181254a7Smrg 
3060181254a7Smrg     static assert( hasElaborateDestructor!(Variant));
3061181254a7Smrg     static assert(!hasElaborateDestructor!(Algebraic!bool));
3062181254a7Smrg     static assert( hasElaborateDestructor!(Algebraic!S));
3063181254a7Smrg     static assert( hasElaborateDestructor!(Algebraic!(bool, S)));
3064181254a7Smrg 
3065181254a7Smrg     import std.array;
3066181254a7Smrg     alias Value = Algebraic!bool;
3067181254a7Smrg 
3068181254a7Smrg     static struct T
3069181254a7Smrg     {
3070181254a7Smrg         Value value;
3071181254a7Smrg         @disable this();
3072181254a7Smrg     }
3073181254a7Smrg     auto a = appender!(T[]);
3074181254a7Smrg }
3075181254a7Smrg 
3076*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=13871
3077181254a7Smrg @system unittest
3078181254a7Smrg {
3079181254a7Smrg     alias A = Algebraic!(int, typeof(null));
3080181254a7Smrg     static struct B { A value; }
3081181254a7Smrg     alias C = std.variant.Algebraic!B;
3082181254a7Smrg 
3083181254a7Smrg     C var;
3084181254a7Smrg     var = C(B());
3085181254a7Smrg }
3086181254a7Smrg 
3087181254a7Smrg @system unittest
3088181254a7Smrg {
3089181254a7Smrg     import std.exception : assertThrown, assertNotThrown;
3090181254a7Smrg     // Make sure Variant can handle types with opDispatch but no length field.
3091181254a7Smrg     struct SWithNoLength
3092181254a7Smrg     {
3093181254a7Smrg         void opDispatch(string s)() { }
3094181254a7Smrg     }
3095181254a7Smrg 
3096181254a7Smrg     struct SWithLength
3097181254a7Smrg     {
3098181254a7Smrg         @property int opDispatch(string s)()
3099181254a7Smrg         {
3100181254a7Smrg             // Assume that s == "length"
3101181254a7Smrg             return 5; // Any value is OK for test.
3102181254a7Smrg         }
3103181254a7Smrg     }
3104181254a7Smrg 
3105181254a7Smrg     SWithNoLength sWithNoLength;
3106181254a7Smrg     Variant v = sWithNoLength;
3107181254a7Smrg     assertThrown!VariantException(v.length);
3108181254a7Smrg 
3109181254a7Smrg     SWithLength sWithLength;
3110181254a7Smrg     v = sWithLength;
3111181254a7Smrg     assertNotThrown!VariantException(v.get!SWithLength.length);
3112181254a7Smrg     assertThrown!VariantException(v.length);
3113181254a7Smrg }
3114181254a7Smrg 
3115*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=13534
3116181254a7Smrg @system unittest
3117181254a7Smrg {
3118181254a7Smrg     static assert(!__traits(compiles, () @safe {
3119181254a7Smrg         auto foo() @system { return 3; }
3120181254a7Smrg         auto v = Variant(&foo);
3121181254a7Smrg         v(); // foo is called in safe code!?
3122181254a7Smrg     }));
3123181254a7Smrg }
3124181254a7Smrg 
3125*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=15039
3126181254a7Smrg @system unittest
3127181254a7Smrg {
3128181254a7Smrg     import std.typecons;
3129181254a7Smrg     import std.variant;
3130181254a7Smrg 
3131181254a7Smrg     alias IntTypedef = Typedef!int;
3132181254a7Smrg     alias Obj = Algebraic!(int, IntTypedef, This[]);
3133181254a7Smrg 
3134181254a7Smrg     Obj obj = 1;
3135181254a7Smrg 
3136181254a7Smrg     obj.visit!(
3137181254a7Smrg         (int x) {},
3138181254a7Smrg         (IntTypedef x) {},
3139181254a7Smrg         (Obj[] x) {},
3140181254a7Smrg     );
3141181254a7Smrg }
3142181254a7Smrg 
3143*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=15791
3144181254a7Smrg @system unittest
3145181254a7Smrg {
3146181254a7Smrg     int n = 3;
3147181254a7Smrg     struct NS1 { int foo() { return n + 10; } }
3148181254a7Smrg     struct NS2 { int foo() { return n * 10; } }
3149181254a7Smrg 
3150181254a7Smrg     Variant v;
3151181254a7Smrg     v = NS1();
3152181254a7Smrg     assert(v.get!NS1.foo() == 13);
3153181254a7Smrg     v = NS2();
3154181254a7Smrg     assert(v.get!NS2.foo() == 30);
3155181254a7Smrg }
3156181254a7Smrg 
3157*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=15827
3158181254a7Smrg @system unittest
3159181254a7Smrg {
3160181254a7Smrg     static struct Foo15827 { Variant v; this(Foo15827 v) {} }
3161181254a7Smrg     Variant v = Foo15827.init;
3162181254a7Smrg }
3163*b1e83836Smrg 
3164*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=18934
3165*b1e83836Smrg @system unittest
3166*b1e83836Smrg {
3167*b1e83836Smrg     static struct S
3168*b1e83836Smrg     {
3169*b1e83836Smrg         const int x;
3170*b1e83836Smrg     }
3171*b1e83836Smrg 
3172*b1e83836Smrg     auto s = S(42);
3173*b1e83836Smrg     Variant v = s;
3174*b1e83836Smrg     auto s2 = v.get!S;
3175*b1e83836Smrg     assert(s2.x == 42);
3176*b1e83836Smrg     Variant v2 = v; // support copying from one variant to the other
3177*b1e83836Smrg     v2 = S(2);
3178*b1e83836Smrg     v = v2;
3179*b1e83836Smrg     assert(v.get!S.x == 2);
3180*b1e83836Smrg }
3181*b1e83836Smrg 
3182*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=19200
3183*b1e83836Smrg @system unittest
3184*b1e83836Smrg {
3185*b1e83836Smrg     static struct S
3186*b1e83836Smrg     {
3187*b1e83836Smrg         static int opBinaryRight(string op : "|", T)(T rhs)
3188*b1e83836Smrg         {
3189*b1e83836Smrg             return 3;
3190*b1e83836Smrg         }
3191*b1e83836Smrg     }
3192*b1e83836Smrg 
3193*b1e83836Smrg     S s;
3194*b1e83836Smrg     Variant v;
3195*b1e83836Smrg     auto b = v | s;
3196*b1e83836Smrg     assert(b == 3);
3197*b1e83836Smrg }
3198*b1e83836Smrg 
3199*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=11061
3200*b1e83836Smrg @system unittest
3201*b1e83836Smrg {
3202*b1e83836Smrg     int[4] el = [0, 1, 2, 3];
3203*b1e83836Smrg     int[3] nl = [0, 1, 2];
3204*b1e83836Smrg     Variant v1 = el;
3205*b1e83836Smrg     assert(v1 == el); // Compare Var(static) to static
3206*b1e83836Smrg     assert(v1 != nl); // Compare static arrays of different length
3207*b1e83836Smrg     assert(v1 == [0, 1, 2, 3]); // Compare Var(static) to dynamic.
3208*b1e83836Smrg     assert(v1 != [0, 1, 2]);
3209*b1e83836Smrg     int[] dyn = [0, 1, 2, 3];
3210*b1e83836Smrg     v1 = dyn;
3211*b1e83836Smrg     assert(v1 == el); // Compare Var(dynamic) to static.
3212*b1e83836Smrg     assert(v1 == [0, 1] ~ [2, 3]); // Compare Var(dynamic) to dynamic
3213*b1e83836Smrg }
3214*b1e83836Smrg 
3215*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=15940
3216*b1e83836Smrg @system unittest
3217*b1e83836Smrg {
3218*b1e83836Smrg     class C { }
3219*b1e83836Smrg     struct S
3220*b1e83836Smrg     {
3221*b1e83836Smrg         C a;
3222*b1e83836Smrg         alias a this;
3223*b1e83836Smrg     }
3224*b1e83836Smrg     S s = S(new C());
3225*b1e83836Smrg     auto v = Variant(s); // compile error
3226*b1e83836Smrg }
3227*b1e83836Smrg 
3228*b1e83836Smrg @system unittest
3229*b1e83836Smrg {
3230*b1e83836Smrg     // Test if we don't have scoping issues.
3231*b1e83836Smrg     Variant createVariant(int[] input)
3232*b1e83836Smrg     {
3233*b1e83836Smrg         int[2] el = [input[0], input[1]];
3234*b1e83836Smrg         Variant v = el;
3235*b1e83836Smrg         return v;
3236*b1e83836Smrg     }
3237*b1e83836Smrg     Variant v = createVariant([0, 1]);
3238*b1e83836Smrg     createVariant([2, 3]);
3239*b1e83836Smrg     assert(v == [0,1]);
3240*b1e83836Smrg }
3241*b1e83836Smrg 
3242*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=19994
3243*b1e83836Smrg @safe unittest
3244*b1e83836Smrg {
3245*b1e83836Smrg     alias Inner = Algebraic!(This*);
3246*b1e83836Smrg     alias Outer = Algebraic!(Inner, This*);
3247*b1e83836Smrg 
3248*b1e83836Smrg     static assert(is(Outer.AllowedTypes == AliasSeq!(Inner, Outer*)));
3249*b1e83836Smrg }
3250*b1e83836Smrg 
3251*b1e83836Smrg // https://issues.dlang.org/show_bug.cgi?id=21296
3252*b1e83836Smrg @system unittest
3253*b1e83836Smrg {
3254*b1e83836Smrg     immutable aa = ["0": 0];
3255*b1e83836Smrg     auto v = Variant(aa); // compile error
3256*b1e83836Smrg }
3257