Find a file
Sönke Ludwig 8166b54b12 Let errors in generic visitors through.
Avoids the visit!() instantiation failing early and hiding the concrete source of the error.
2021-01-05 10:48:33 +01:00
.github/workflows Add GitHub test action. 2021-01-05 10:48:16 +01:00
source/taggedalgebraic Let errors in generic visitors through. 2021-01-05 10:48:33 +01:00
.codecov.yml Switch to codecov.io. 2018-01-18 00:02:06 +01:00
.editorconfig Add .travis.yml and .editorconfig. See #2. 2016-01-27 23:02:37 +01:00
.gitignore Use a more modern .gitignore 2019-06-20 16:33:27 +09:00
.travis.yml ci: enable use of meson again 2020-04-17 19:14:48 +02:00
dub.sdl Enable dip1000, drop support for < 2.085.1, test on OSX 2020-02-04 13:45:42 +09:00
meson.build Bump meson project version number. 2020-05-12 14:32:17 +02:00
README.md Update build status badge to travis-ci-com 2020-04-04 12:34:49 +02:00
travis.sh Fix unbound variable error in test script. 2020-05-12 14:24:26 +02:00

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 codecov

API Documentation:

Usage of TaggedUnion

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.countValue == 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.strValue == "bar");

// Modify contained value by reference
taggedAny.strValue = "baz";
assert(taggedAny.strValue == "baz");

// In addition to the getter, the contained value can be extracted using get!()
// or by casting
assert(taggedInt.value!(TUnion.Kind.count) == 5);
assert(taggedInt.value!int == 5);
assert(cast(byte)taggedInt == 5);

// Multiple kinds of the same type are supported
taggedAny.setOffset(5);
assert(taggedAny.isOffset);
assert(!taggedAny.isCount);

// Unique types can also be set directly
taggedAny = "foo";
assert(taggedAny.isStr);
taggedAny = TUnion(Foo.init);
assert(taggedAny.isFoo);

Usage of TaggedAlgebraic

import taggedalgebraic;

struct Foo {
	string name;
	void bar() {}
}

union Base {
	int i;
	string str;
	Foo foo;
}

alias TAlgebraic = TaggedAlgebraic!Base;

// Instantiate
TAlgebraic taggedInt = 5;
TAlgebraic taggedString = "Hello";
TAlgebraic taggedFoo = Foo();
TAlgebraic taggedAny = taggedInt;
taggedAny = taggedString;
taggedAny = taggedFoo;

// 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 == TAlgebraic.Kind.foo) // Make sure to check type first!
	taggedAny.bar();
//taggedString.bar(); // AssertError: Not a Foo!

// Convert back by casting
auto i   = cast(int)    taggedInt;
auto str = cast(string) taggedString;
auto foo = cast(Foo)    taggedFoo;
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 TAlgebraic.Kind.i:
		// It's "int i"
		break;

	case TAlgebraic.Kind.str:
		// It's "string str"
		break;

	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.088.0
  • LDC 1.6.0 up to 1.17.0