diff --git a/README.md b/README.md index 9d360ab..589d2d7 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,81 @@ TaggedAlgebraic =============== -Implementation of a generic algebraic data type with a tagged union storage. All operations of the contained types are available for the `TaggedAlgebraic` +Implementation of a generic `TaggedUnion` type along with a `TaggedAlgebraic` type that forwards all methods and operators of the contained types using dynamic dispatch. [![Build Status](https://travis-ci.org/s-ludwig/taggedalgebraic.svg?branch=master)](https://travis-ci.org/s-ludwig/taggedalgebraic) [![codecov](https://codecov.io/gh/s-ludwig/taggedalgebraic/branch/master/graph/badge.svg)](https://codecov.io/gh/s-ludwig/taggedalgebraic) -Usage ------ +Usage of `TaggedUnion` +---------------------- + +```d +import taggedalgebraic; + +struct Foo { + string name; + void bar() {} +} + +union Base { + int count; + int offset; + string str; + Foo foo; +} + +alias TUnion = TaggedUnion!Base; + +// Instantiate +TUnion taggedInt = TUnion.count(5); +TUnion taggedString = TUnion.str("Hello"); +TUnion taggedFoo = TUnion.foo; +TUnion taggedAny = taggedInt; +taggedAny = taggedString; +taggedAny = taggedFoo; + +// Default initializes to the first field +TUnion taggedDef; +assert(taggedDef.isCount); +assert(taggedDef.getCount == int.init); + +// Check type: TUnion.Kind is an enum +assert(taggedInt.kind == TUnion.Kind.count); +assert(taggedString.kind == TUnion.Kind.str); +assert(taggedFoo.kind == TUnion.Kind.foo); +assert(taggedAny.kind == TUnion.Kind.foo); + +// A shorter syntax is also available +assert(taggedInt.isCount); +assert(!taggedInt.isOffset); +assert(taggedString.isStr); +assert(taggedFoo.isFoo); +assert(taggedAny.isFoo); + +// Set to a different type +taggedAny.setStr("bar"); +assert(taggedAny.isStr); +assert(taggedAny.getStr() == "bar"); + +// Modify contained value by reference +taggedAny.getStr() = "baz"; +assert(taggedAny.getStr() == "baz"); + +// In addition to the getter, the contained value can be extracted using get!() +// or by casting +assert(taggedInt.get!(TUnion.Kind.count) == 5); +assert(taggedInt.get!int == 5); +assert(cast(byte)taggedInt == 5); + +// Multiple kinds of the same type are supported +taggedAny.setOffset(5); +assert(taggedAny.isOffset); +assert(taggedAny.isCount); +``` + + +Usage of `TaggedAlgebraic` +-------------------------- ```d import taggedalgebraic; @@ -23,27 +91,27 @@ union Base { Foo foo; } -alias Tagged = TaggedAlgebraic!Base; +alias TAlgebraic = TaggedAlgebraic!Base; // Instantiate -Tagged taggedInt = 5; -Tagged taggedString = "Hello"; -Tagged taggedFoo = Foo(); -Tagged taggedAny = taggedInt; +TAlgebraic taggedInt = 5; +TAlgebraic taggedString = "Hello"; +TAlgebraic taggedFoo = Foo(); +TAlgebraic taggedAny = taggedInt; taggedAny = taggedString; taggedAny = taggedFoo; -// Check type: Tagged.Kind is an enum -assert(taggedInt.kind == Tagged.Kind.i); -assert(taggedString.kind == Tagged.Kind.str); -assert(taggedFoo.kind == Tagged.Kind.foo); -assert(taggedAny.kind == Tagged.Kind.foo); +// Check type: TAlgebraic.Kind is an enum +assert(taggedInt.kind == TAlgebraic.Kind.i); +assert(taggedString.kind == TAlgebraic.Kind.str); +assert(taggedFoo.kind == TAlgebraic.Kind.foo); +assert(taggedAny.kind == TAlgebraic.Kind.foo); // In most cases, can simply use as-is auto num = 4 + taggedInt; auto msg = taggedString ~ " World!"; taggedFoo.bar(); -if (taggedAny.kind == Tagged.Kind.foo) // Make sure to check type first! +if (taggedAny.kind == TAlgebraic.Kind.foo) // Make sure to check type first! taggedAny.bar(); //taggedString.bar(); // AssertError: Not a Foo! @@ -51,22 +119,30 @@ if (taggedAny.kind == Tagged.Kind.foo) // Make sure to check type first! auto i = cast(int) taggedInt; auto str = cast(string) taggedString; auto foo = cast(Foo) taggedFoo; -if (taggedAny.kind == Tagged.Kind.foo) // Make sure to check type first! +if (taggedAny.kind == TAlgebraic.Kind.foo) // Make sure to check type first! auto foo2 = cast(Foo) taggedAny; //cast(Foo) taggedString; // AssertError! // Kind is an enum, so final switch is supported: final switch (taggedAny.kind) { - case Tagged.Kind.i: + case TAlgebraic.Kind.i: // It's "int i" break; - case Tagged.Kind.str: + case TAlgebraic.Kind.str: // It's "string str" break; - case Tagged.Kind.foo: + case TAlgebraic.Kind.foo: // It's "Foo foo" break; } ``` + +Compiler support +---------------- + +The library is tested to work on the following compilers: + +- DMD 2.076.1 up to 2.084.1 +- LDC 1.6.0 up to 1.14.0