vsignal ~master

A multipurpose Signal library

To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:


A Signals/Slots implementation in D. This implementation is based on the pattern used in ENTT.

A Signal is declared with a delegate:

Signal!(void delegate(int)) sig;

To connect listeners a function pointer, lambda, or delegate can be passed:

void foo(const int) {}

sig.sink.connect!((int) {});

Forward is applied when possible. However, in D forward treats lvalues as rvalues to fix the ambiguity problem (see here). To go around the situations when trying to move does not work, Signal fallsback to the normal execution for that variable and does a copy.

This can cause a slight bump in the execution speed when using a Signal!(void delegate(int)) and connecting a void delegate(ref int) listener for example.

When connecting lambdas the parameters can be omitted:

sig.sink.connect((_) {});
sig.sink.connect((const _) {});
sig.sink.connect((ref _) {});
sig.sink.connect((ref const _) {});

Signal also accepts connecting listeners from instances:

struct Listener
	void opCall(const int) {}

Listener listener;


As seen above, it is possible to attach an instance to a Slot. This also has some advantages for structuring the code internally. It also allows the user to specify a listener that receives a ref. Take a look at the following:

void bar(immutable ref int, int) {}
immutable int var = 5;


As seen, the Signal is still void delegate(int) however, the Slot that contains the listener bar also has attached the payload var, which will be passed to the function's first argument.

Listener connection must be executed with Sink. As seen throughout this explanation, all examples use sink before connecting a listener. This allows for Signal to be declared privately internally to omit emit functionality to the user. The user receives a Sink a works with it to connect and disconnect listeners. The Sink also returns another data structure to help managing listeners. The Connection structure is returned every time a connection is made. Connection allows the user to break a connection without having to rely on managing Signal or Sink instances.

Signal usage example:

@safe void foo(immutable ref Listener, int) {}
@safe void bar(int) {}

@safe struct Listener
	void opCall(const int) {}

void main() @safe
	Signal!(void delegate(int) @safe) sig;

	// this can be @trusted because sink's lifetime is lower than sig's.
	auto sink = () @trusted { return sig.sink; } ();

	with (sig.sink)

		Listener listener;

		// connecting
		auto connection = sink.connect!((ref _) {});


		// disconnect a listener with an instance

		// disconnect a listener

		// disconnect all listeners with an instance

		// disconnect all listeners

		// for lambdas the connection must be used

Licensed under:


If you are interested in project and want to improve it, creating issues and pull requests are highly appretiated!

  • João Lourenço
0.1.0 2021-Sep-17
~master 2021-Sep-17
Show all 2 versions
Download Stats:
  • 0 downloads today

  • 0 downloads this week

  • 0 downloads this month

  • 352 downloads total

Short URL: