| @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); |
| } |
| |