module concurrency.operations.finally_; import concurrency; import concurrency.receiver; import concurrency.sender; import concurrency.stoptoken; import concepts; import std.traits; auto finally_(Sender, Result)(Sender sender, Result result) { import std.traits : isCallable; return FinallySender!(Sender, Result)(sender, result); } private struct FinallyReceiver(Value, Result, Receiver) { Receiver receiver; Result result; private auto getResult() { static if (isCallable!Result) return result(); else return result; } static if (is(Value == void)) void setValue() @safe { receiver.setValue(getResult()); } else void setValue(Value value) @safe { receiver.setValue(getResult()); } void setDone() @safe nothrow { receiver.setDone(); } void setError(Exception e) @safe nothrow { receiver.setValue(getResult()); } mixin ForwardExtensionPoints!receiver; } struct FinallySender(Sender, Result) if (models!(Sender, isSender)) { static assert (models!(typeof(this), isSender)); static if (isCallable!Result) alias Value = typeof(result()); else alias Value = Result; Sender sender; Result result; auto connect(Receiver)(return Receiver receiver) @safe scope return { // ensure NRVO auto op = sender.connect(FinallyReceiver!(Sender.Value, Result, Receiver)(receiver, result)); return op; } }