voile.handler

Common Handler type
template DelegateTypeOf(F) if (isCallable!F)
template DelegateTypeOf(alias F) if (isCallable!F)
template isCastableDelegate(aFunc, bFunc)
struct Handler(F) if (isCallable!F && (is(ReturnType!F == void) || is(ReturnType!F : bool)));
Generic Handler
複数のコールバックを登録し、同じ引数でまとめて呼び出すことのできる構造体です。 コールバックには以下の種類のデータを使用できます。
  • 関数ポインタ
  • デリゲート
  • opCallを持つ集合型(class, struct, union, interface)のインスタンス
  • core.thread.Fiber
  • std.concurrency.Tid
  • OutputRange
基本的な流れは、接続(connect)でコールバックを追加して、実行(emit)でコールバックを呼び出して、 コールバックが不要になったら切断(disconnect)します。
  • 接続:connect関数または ~= 演算子にて、コールバックを追加することができます。
    • connect関数の戻り値はハンドラ内部でコールバックを管理しているプロシージャIDです。
    • singleShotConnectで、一度だけ実行した後に自動で切断することも可能です。
    • connectした順番で呼び出しが行われます。
  • 切断:disconnect関数によって、コールバックを削除することができます。
    • プロシージャIDを指定して切断することも可能です。
    • 一度切断されたコールバックのプロシージャIDは使用できません。
  • 実行:emit関数または () 演算子にて、コールバックを一斉に呼び出すことができます。
    • 関数ポインタを接続した場合、関数ポインタを呼び出します。
    • デリゲートを接続した場合、デリゲートを呼び出します。
    • 集合型のインスタンスを接続した場合、インスタンスのopCallを呼び出します。
    • Fiberを接続した場合、Fiberのcallを呼び出します。Fが void delegate() の場合だけ有効です。
    • OutputRangeを接続した場合、OutputRangeのputを呼び出します。Fが void delegate(T) のとき、 isOutputRange!(Range, T)の場合だけ有効です。
Note:
  • 実行中に接続・切断ができますが、そのとき実行時にコールバックのリストを複製してから呼び出しているため、 途中操作での接続・切断は反映されません。
  • ハンドラは複製することができません。複製したい場合は、スライスでコールバックへアクセスすることができますので、 明示的にディープコピーを行ってください。その際には、オブジェクトの寿命管理には注意して下さい。
  • ハンドラでコールバックを保持し続ける限り、コールバックに関連するデータ(例えばデリゲートのコンテキスト)は GCで解放されなくなります。
  • 一方でコールバックに関連するデータを手動で破棄した場合には、ハンドラの呼び出しで破棄済みのデータにアクセスする 恐れがあります。ハンドラからの切断を行ってからデータを破棄してください。
  • emit関数は、ハンドラのテンプレートパラメータで指定したFの型により、属性を指定できます。 例えば Handler!(void delegate() nothrow) とすると、emit関数にもnothrow属性がつきます。
  • emit関数の戻り値は、ハンドラのテンプレートパラメータで指定したFの戻り値と同じです。ただし、以下の型限定です。
    • void: 戻り値を返しません。
    • bool: コールバックすべてがtrueを返した場合に、emit関数もtrueを返します。 コールバックが一つでもfalseを返した場合、それ以降コールバック呼び出しを行わず、emit関数もfalseを返します。
Examples: コピー禁止・ムーブ可
import std.algorithm: move;
Handler!(void delegate()) h1;
Handler!(void delegate()) h2;
static assert(!__traits(compiles, h2 = h1));
static assert(__traits(compiles, h2 = h1.move()));
Examples:
int val;
Handler!(void delegate(int test)) h;
h.singleShotConnect((int test) {
	val = test;
});
h(100);
assert(val == 100);
h(200);
assert(val == 100);
RetType emit(Args args);
const RetType emit(Args args);
shared const RetType emit(Args args);
alias opCall = emit;
Proc toConnectable(Func)(auto ref Func fn)
if(is(typeof(toDelegate(fn))) && isCastableDelegate!(Proc, DelegateTypeOf!Func));
Proc toConnectable(Func)(Func tid)
if(is(Func == Tid));
Proc toConnectable(Range)(Range r)
if(Args.length == 1 && isOutputRange!(Range, Args) && !isCallable!Range && (is(Range == class) || is(Range == interface) || isPointer!Range) && is(typeof(() { Range tmp; if (!tmp.empty) { } } )));
Proc toConnectable(Func)(Func fib)
if(is(Func : Fiber));
alias HandlerProcId = ProcList.Iterator;
HandlerProcId connect(Func)(auto ref Func fn)
if(is(typeof(toConnectable(fn))));
Connect
Parameters:
Func fn delegate, function, Tid, Object( has opCall ), Fiber, OutputRange(class or interface or T*, and has empty method)
HandlerProcId singleShotConnect(Func)(Func fn)
if(is(typeof(toConnectable(fn))));
void opOpAssign(string op, Func)(Func dg)
if(op == "~" && is(typeof(connect(dg))));
alias put = connect;
一度だけ実行するハンドラを接続する
HandlerProcId connectedId(Func)(Func fn)
if(is(typeof(toConnectable(fn))));
void opOpAssign(string op, ProcContainer)(auto ref ProcContainer procs)
if(op == "~" && is(ForeachType!(typeof(ProcContainer.init[])) : Proc));
Concut
Parameters:
ProcContainer procs other Handler
auto opSlice();
const pure nothrow bool opCast(T)()
if(is(T == bool));
void disconnect(Func)(Func fn)
if(is(typeof(toConnectable(fn))));
void disconnect(Func)(Func id)
if(is(Func == HandlerProcId));
void disconnect(Func)(Func hnd)
if(is(Func == Handler));
alias remove = disconnect;
void insertAfter(Func)(ProcList.Range r, Func fn)
if(is(typeof(toConnectable(fn))));
void insertAfter(Func)(HandlerProcId needleid, Func fn)
if(is(typeof(toConnectable(fn))));
void insertAfter(Func)(Func needle, Func fn)
if(is(typeof(toConnectable(fn))));
void insertBefore(Func)(ProcList.Range r, Func fn)
if(is(typeof(toConnectable(fn))));
void insertBefore(Func)(HandlerProcId needleid, Func fn)
if(is(typeof(toConnectable(fn))));
void insertBefore(Func)(Func needle, Func fn)
if(is(typeof(toConnectable(fn))));
pure void clear();