| @system unittest | |
| { | |
| import std.variant; | |
| Variant a; // Must assign before use, otherwise exception ensues | |
| // Initialize with an integer; make the type int | |
| Variant b = 42; | |
| assert(b.type == typeid(int)); | |
| // Peek at the value | |
| assert(b.peek!(int) !is null && *b.peek!(int) == 42); | |
| // Automatically convert per language rules | |
| auto x = b.get!(real); | |
| // Assign any other type, including other variants | |
| a = b; | |
| a = 3.14; | |
| assert(a.type == typeid(double)); | |
| // Implicit conversions work just as with built-in types | |
| assert(a < b); | |
| // Check for convertibility | |
| assert(!a.convertsTo!(int)); // double not convertible to int | |
| // Strings and all other arrays are supported | |
| a = "now I'm a string"; | |
| assert(a == "now I'm a string"); | |
| // can also assign arrays | |
| a = new int[42]; | |
| assert(a.length == 42); | |
| a[5] = 7; | |
| assert(a[5] == 7); | |
| // Can also assign class values | |
| class Foo {} | |
| auto foo = new Foo; | |
| a = foo; | |
| assert(*a.peek!(Foo) == foo); // and full type information is preserved | |
| } | |
| @safe unittest | |
| { | |
| import std.variant; | |
| struct Cat { int a, b, c; } | |
| align(1) struct S | |
| { | |
| long l; | |
| ubyte b; | |
| } | |
| align(1) struct T | |
| { | |
| ubyte b; | |
| long l; | |
| } | |
| static assert(maxSize!(int, long) == 8); | |
| static assert(maxSize!(bool, byte) == 1); | |
| static assert(maxSize!(bool, Cat) == 12); | |
| static assert(maxSize!(char) == 1); | |
| static assert(maxSize!(char, short, ubyte) == 2); | |
| static assert(maxSize!(char, long, ubyte) == 8); | |
| import std.algorithm.comparison : max; | |
| static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof)); | |
| static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof)); | |
| static assert(maxSize!(int, ubyte[7]) == 7); | |
| static assert(maxSize!(int, ubyte[3]) == 4); | |
| static assert(maxSize!(int, int, ubyte[3]) == 4); | |
| static assert(maxSize!(void, int, ubyte[3]) == 4); | |
| static assert(maxSize!(void) == 1); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| alias Var = VariantN!(maxSize!(int, double, string)); | |
| Var a; // Must assign before use, otherwise exception ensues | |
| // Initialize with an integer; make the type int | |
| Var b = 42; | |
| assert(b.type == typeid(int)); | |
| // Peek at the value | |
| assert(b.peek!(int) !is null && *b.peek!(int) == 42); | |
| // Automatically convert per language rules | |
| auto x = b.get!(real); | |
| // Assign any other type, including other variants | |
| a = b; | |
| a = 3.14; | |
| assert(a.type == typeid(double)); | |
| // Implicit conversions work just as with built-in types | |
| assert(a < b); | |
| // Check for convertibility | |
| assert(!a.convertsTo!(int)); // double not convertible to int | |
| // Strings and all other arrays are supported | |
| a = "now I'm a string"; | |
| assert(a == "now I'm a string"); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| alias Var = VariantN!(maxSize!(int[])); | |
| Var a = new int[42]; | |
| assert(a.length == 42); | |
| a[5] = 7; | |
| assert(a[5] == 7); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| alias Var = VariantN!(maxSize!(int*)); // classes are pointers | |
| Var a; | |
| class Foo {} | |
| auto foo = new Foo; | |
| a = foo; | |
| assert(*a.peek!(Foo) == foo); // and full type information is preserved | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| auto v = Algebraic!(int, double, string)(5); | |
| assert(v.peek!(int)); | |
| v = 3.14; | |
| assert(v.peek!(double)); | |
| // auto x = v.peek!(long); // won't compile, type long not allowed | |
| // v = '1'; // won't compile, type char not allowed | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| import std.typecons : Tuple, tuple; | |
| // A tree is either a leaf or a branch of two other trees | |
| alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*)); | |
| Tree!int tree = tuple(new Tree!int(42), new Tree!int(43)); | |
| Tree!int* right = tree.get!1[1]; | |
| assert(*right == 43); | |
| // An object is a double, a string, or a hash of objects | |
| alias Obj = Algebraic!(double, string, This[string]); | |
| Obj obj = "hello"; | |
| assert(obj.get!1 == "hello"); | |
| obj = 42.0; | |
| assert(obj.get!0 == 42); | |
| obj = ["customer": Obj("John"), "paid": Obj(23.95)]; | |
| assert(obj.get!2["customer"] == "John"); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| Variant a; // Must assign before use, otherwise exception ensues | |
| // Initialize with an integer; make the type int | |
| Variant b = 42; | |
| assert(b.type == typeid(int)); | |
| // Peek at the value | |
| assert(b.peek!(int) !is null && *b.peek!(int) == 42); | |
| // Automatically convert per language rules | |
| auto x = b.get!(real); | |
| // Assign any other type, including other variants | |
| a = b; | |
| a = 3.14; | |
| assert(a.type == typeid(double)); | |
| // Implicit conversions work just as with built-in types | |
| assert(a < b); | |
| // Check for convertibility | |
| assert(!a.convertsTo!(int)); // double not convertible to int | |
| // Strings and all other arrays are supported | |
| a = "now I'm a string"; | |
| assert(a == "now I'm a string"); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| Variant a = new int[42]; | |
| assert(a.length == 42); | |
| a[5] = 7; | |
| assert(a[5] == 7); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| Variant a; | |
| class Foo {} | |
| auto foo = new Foo; | |
| a = foo; | |
| assert(*a.peek!(Foo) == foo); // and full type information is preserved | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| auto a = variantArray(1, 3.14, "Hi!"); | |
| assert(a[1] == 3.14); | |
| auto b = Variant(a); // variant array as variant | |
| assert(b[1] == 3.14); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| import std.exception : assertThrown; | |
| Variant v; | |
| // uninitialized use | |
| assertThrown!VariantException(v + 1); | |
| assertThrown!VariantException(v.length); | |
| // .get with an incompatible target type | |
| assertThrown!VariantException(Variant("a").get!int); | |
| // comparison between incompatible types | |
| assertThrown!VariantException(Variant(3) < Variant("a")); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| Algebraic!(int, string) variant; | |
| variant = 10; | |
| assert(variant.visit!((string s) => cast(int) s.length, | |
| (int i) => i)() | |
| == 10); | |
| variant = "string"; | |
| assert(variant.visit!((int i) => i, | |
| (string s) => cast(int) s.length)() | |
| == 6); | |
| // Error function usage | |
| Algebraic!(int, string) emptyVar; | |
| auto rslt = emptyVar.visit!((string s) => cast(int) s.length, | |
| (int i) => i, | |
| () => -1)(); | |
| assert(rslt == -1); | |
| // Generic function usage | |
| Algebraic!(int, float, real) number = 2; | |
| assert(number.visit!(x => x += 1) == 3); | |
| // Generic function for int/float with separate behavior for string | |
| Algebraic!(int, float, string) something = 2; | |
| assert(something.visit!((string s) => s.length, x => x) == 2); // generic | |
| something = "asdf"; | |
| assert(something.visit!((string s) => s.length, x => x) == 4); // string | |
| // Generic handler and empty handler | |
| Algebraic!(int, float, real) empty2; | |
| assert(empty2.visit!(x => x + 1, () => -1) == -1); | |
| } | |
| @system unittest | |
| { | |
| import std.variant; | |
| Algebraic!(int, string) variant; | |
| variant = 10; | |
| auto which = -1; | |
| variant.tryVisit!((int i) { which = 0; })(); | |
| assert(which == 0); | |
| // Error function usage | |
| variant = "test"; | |
| variant.tryVisit!((int i) { which = 0; }, | |
| () { which = -100; })(); | |
| assert(which == -100); | |
| } | |