private void ProcessEvent(int connection)
{
// this must be the state after returning without delivering any signals, to avoid double-finalization of some unlucky stage
// (this can happen if a stage completes voluntarily while connection close events are still queued)
ActiveStage = null;
var code = PortStates[connection];
// Manual fast decoding, fast paths are PUSH and PULL
if ((code & (Pushing | InClosed | OutClosed)) == Pushing)
{
// PUSH
ProcessElement(connection);
}
else if ((code & (Pulling | OutClosed | InClosed)) == Pulling)
{
// PULL
if (IsDebug) Console.WriteLine($"{Name} PULL {InOwnerName(connection)} -> {OutOwnerName(connection)} ({OutHandlers[connection]}) [{OutLogicName(connection)}]");
PortStates[connection] ^= PullEndFlip;
ActiveStage = SafeLogics(Assembly.OutletOwners[connection]);
OutHandlers[connection].OnPull();
}
else if ((code & (OutClosed | InClosed)) == InClosed)
{
// CANCEL
var stageId = Assembly.OutletOwners[connection];
ActiveStage = SafeLogics(stageId);
if (IsDebug) Console.WriteLine($"{Name} CANCEL {InOwnerName(connection)} -> {OutOwnerName(connection)} ({OutHandlers[connection]}) [{OutLogicName(connection)}]");
PortStates[connection] |= OutClosed;
CompleteConnection(stageId);
OutHandlers[connection].OnDownstreamFinish();
}
else if ((code & (OutClosed | InClosed)) == OutClosed)
{
// COMPLETIONS
if ((code & Pushing) == 0)
{
// Normal completion (no push pending)
if (IsDebug) Console.WriteLine($"{Name} COMPLETE {OutOwnerName(connection)} -> {InOwnerName(connection)} ({InHandlers[connection]}) [{InLogicName(connection)}]");
PortStates[connection] |= InClosed;
var stageId = Assembly.InletOwners[connection];
ActiveStage = SafeLogics(stageId);
CompleteConnection(stageId);
if ((PortStates[connection] & InFailed) == 0)
InHandlers[connection].OnUpstreamFinish();
else
InHandlers[connection].OnUpstreamFailure(((Failed)ConnectionSlots[connection]).Reason);
}
else
{
// Push is pending, first process push, then re-enqueue closing event
ProcessElement(connection);
Enqueue(connection);
}
}
}