com.wallstop-studios.dxmessaging 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +286 -0
- package/Editor/Analyzers/BaseCallLogMessageParser.cs.meta +3 -3
- package/Editor/Analyzers/BaseCallReportAggregator.cs.meta +3 -3
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs.meta +3 -3
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs.meta +3 -3
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs.meta +3 -3
- package/Editor/DxMessagingMenu.cs.meta +3 -3
- package/Editor/DxMessagingSceneBuildProcessor.cs.meta +3 -3
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +2 -3
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs.meta +3 -3
- package/Editor/SetupCscRsp.cs +232 -163
- package/README.md +1 -1
- package/Runtime/Analyzers.meta +8 -0
- package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs.meta +3 -3
- package/Runtime/Core/DxMessagingStaticState.cs.meta +3 -3
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +3 -3
- package/Runtime/Core/Extensions/MessageExtensions.cs.meta +3 -3
- package/Runtime/Core/IMessage.cs.meta +3 -3
- package/Runtime/Core/InstanceId.cs.meta +3 -3
- package/Runtime/Core/Internal/TypedSlots.cs +42 -0
- package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +3 -3
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageBus.cs +63 -28
- package/Runtime/Core/MessageBus/IMessageBus.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessageBus.cs +548 -474
- package/Runtime/Core/MessageBus/MessageBus.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessageBusRegistration.cs +207 -0
- package/Runtime/Core/MessageBus/MessageBusRegistration.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +3 -3
- package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +3 -3
- package/Runtime/Core/MessageHandler.cs +1210 -394
- package/Runtime/Core/MessageHandler.cs.meta +3 -3
- package/Runtime/Core/MessageRegistrationHandle.cs.meta +3 -3
- package/Runtime/Core/MessageRegistrationToken.cs +1296 -819
- package/Runtime/Core/MessageRegistrationToken.cs.meta +3 -3
- package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/ITargetedMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +3 -3
- package/Runtime/Core/MessagingDebug.cs.meta +3 -3
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +3 -3
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +3 -3
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +3 -3
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +3 -3
- package/Runtime/Unity/MessageAwareComponent.cs.meta +3 -3
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +3 -3
- package/Runtime/Unity/MessagingComponent.cs.meta +3 -3
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +3 -3
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +3 -3
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +3 -3
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +3 -3
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +3 -3
- package/Samples~/Mini Combat/Boot.cs.meta +3 -3
- package/Samples~/Mini Combat/Enemy.cs.meta +3 -3
- package/Samples~/Mini Combat/Messages.cs.meta +3 -3
- package/Samples~/Mini Combat/Player.cs.meta +3 -3
- package/Samples~/Mini Combat/UIOverlay.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/Messages.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +3 -3
- package/SourceGenerators/Directory.Build.props +5 -5
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +3 -3
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +12 -11
- package/package.json +6 -3
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Collections.Immutable.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Collections.Immutable.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Reflection.Metadata.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Reflection.Metadata.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +0 -0
- /package/{Editor → Runtime}/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +0 -0
|
@@ -2562,7 +2562,10 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2562
2562
|
}
|
|
2563
2563
|
|
|
2564
2564
|
/// <inheritdoc />
|
|
2565
|
-
public
|
|
2565
|
+
public MessageBusRegistration RegisterUntargeted<T>(
|
|
2566
|
+
MessageHandler messageHandler,
|
|
2567
|
+
int priority = 0
|
|
2568
|
+
)
|
|
2566
2569
|
where T : IUntargetedMessage
|
|
2567
2570
|
{
|
|
2568
2571
|
EnsureAotUntargetedBridge<T>();
|
|
@@ -2575,7 +2578,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2575
2578
|
}
|
|
2576
2579
|
|
|
2577
2580
|
/// <inheritdoc />
|
|
2578
|
-
public
|
|
2581
|
+
public MessageBusRegistration RegisterTargeted<T>(
|
|
2579
2582
|
InstanceId target,
|
|
2580
2583
|
MessageHandler messageHandler,
|
|
2581
2584
|
int priority = 0
|
|
@@ -2593,7 +2596,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2593
2596
|
}
|
|
2594
2597
|
|
|
2595
2598
|
/// <inheritdoc />
|
|
2596
|
-
public
|
|
2599
|
+
public MessageBusRegistration RegisterSourcedBroadcast<T>(
|
|
2597
2600
|
InstanceId source,
|
|
2598
2601
|
MessageHandler messageHandler,
|
|
2599
2602
|
int priority = 0
|
|
@@ -2611,7 +2614,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2611
2614
|
}
|
|
2612
2615
|
|
|
2613
2616
|
/// <inheritdoc />
|
|
2614
|
-
public
|
|
2617
|
+
public MessageBusRegistration RegisterSourcedBroadcastWithoutSource<T>(
|
|
2615
2618
|
MessageHandler messageHandler,
|
|
2616
2619
|
int priority = 0
|
|
2617
2620
|
)
|
|
@@ -2627,7 +2630,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2627
2630
|
}
|
|
2628
2631
|
|
|
2629
2632
|
/// <inheritdoc />
|
|
2630
|
-
public
|
|
2633
|
+
public MessageBusRegistration RegisterTargetedWithoutTargeting<T>(
|
|
2631
2634
|
MessageHandler messageHandler,
|
|
2632
2635
|
int priority = 0
|
|
2633
2636
|
)
|
|
@@ -2643,7 +2646,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2643
2646
|
}
|
|
2644
2647
|
|
|
2645
2648
|
/// <inheritdoc />
|
|
2646
|
-
public
|
|
2649
|
+
public MessageBusRegistration RegisterGlobalAcceptAll(MessageHandler messageHandler)
|
|
2647
2650
|
{
|
|
2648
2651
|
long touchTick = AdvanceTick();
|
|
2649
2652
|
InvalidateDispatchPlans();
|
|
@@ -2689,88 +2692,107 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2689
2692
|
|
|
2690
2693
|
long capturedGeneration = _resetGeneration;
|
|
2691
2694
|
long capturedSweepGeneration = _globalSlotSweepGeneration;
|
|
2692
|
-
return (
|
|
2695
|
+
return new MessageBusRegistration(
|
|
2696
|
+
MessageBusRegistration.Kind.GlobalAcceptAll,
|
|
2697
|
+
RegistrationMethod.GlobalAcceptAll,
|
|
2698
|
+
0,
|
|
2699
|
+
capturedGeneration,
|
|
2700
|
+
capturedSweepGeneration,
|
|
2701
|
+
touchTick,
|
|
2702
|
+
null,
|
|
2703
|
+
null,
|
|
2704
|
+
messageHandler,
|
|
2705
|
+
default
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
/// <summary>
|
|
2710
|
+
/// Re-expression of the former <see cref="RegisterGlobalAcceptAll"/> closure body: the
|
|
2711
|
+
/// global accept-all deregistration. Behaviour and both generation guards are unchanged.
|
|
2712
|
+
/// </summary>
|
|
2713
|
+
private void DeregisterGlobalAcceptAll(in MessageBusRegistration reg)
|
|
2714
|
+
{
|
|
2715
|
+
// Generation guard: see DeregisterScalarHandler. The global slot guards on BOTH the
|
|
2716
|
+
// reset generation and the global-slot sweep generation.
|
|
2717
|
+
if (
|
|
2718
|
+
reg.generation != _resetGeneration
|
|
2719
|
+
|| reg.sweepGeneration != _globalSlotSweepGeneration
|
|
2720
|
+
)
|
|
2693
2721
|
{
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
MessageHandler messageHandler = (MessageHandler)reg.payload;
|
|
2726
|
+
Type type = typeof(IMessage);
|
|
2727
|
+
|
|
2728
|
+
long deregisterTouchTick = AdvanceTick();
|
|
2729
|
+
InvalidateDispatchPlans();
|
|
2730
|
+
_globalSlots.version++;
|
|
2731
|
+
_log.Log(
|
|
2732
|
+
new MessagingRegistration(
|
|
2733
|
+
messageHandler.owner,
|
|
2734
|
+
type,
|
|
2735
|
+
RegistrationType.Deregister,
|
|
2736
|
+
RegistrationMethod.GlobalAcceptAll
|
|
2699
2737
|
)
|
|
2738
|
+
);
|
|
2739
|
+
if (!_globalSlots.sharedHandlers.TryGetValue(messageHandler, out int count))
|
|
2740
|
+
{
|
|
2741
|
+
if (MessagingDebug.enabled)
|
|
2700
2742
|
{
|
|
2701
|
-
|
|
2743
|
+
MessagingDebug.Log(
|
|
2744
|
+
LogLevel.Error,
|
|
2745
|
+
"Received over-deregistration of GlobalAcceptAll for MessageHandler {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
2746
|
+
messageHandler
|
|
2747
|
+
);
|
|
2702
2748
|
}
|
|
2703
2749
|
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
_globalSlots.version++;
|
|
2707
|
-
_log.Log(
|
|
2708
|
-
new MessagingRegistration(
|
|
2709
|
-
messageHandler.owner,
|
|
2710
|
-
type,
|
|
2711
|
-
RegistrationType.Deregister,
|
|
2712
|
-
RegistrationMethod.GlobalAcceptAll
|
|
2713
|
-
)
|
|
2714
|
-
);
|
|
2715
|
-
if (!_globalSlots.sharedHandlers.TryGetValue(messageHandler, out count))
|
|
2716
|
-
{
|
|
2717
|
-
if (MessagingDebug.enabled)
|
|
2718
|
-
{
|
|
2719
|
-
MessagingDebug.Log(
|
|
2720
|
-
LogLevel.Error,
|
|
2721
|
-
"Received over-deregistration of GlobalAcceptAll for MessageHandler {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
2722
|
-
messageHandler
|
|
2723
|
-
);
|
|
2724
|
-
}
|
|
2725
|
-
|
|
2726
|
-
return;
|
|
2727
|
-
}
|
|
2750
|
+
return;
|
|
2751
|
+
}
|
|
2728
2752
|
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
}
|
|
2753
|
+
_globalSlots.lastTouchTicks = deregisterTouchTick;
|
|
2754
|
+
if (count <= 1)
|
|
2755
|
+
{
|
|
2756
|
+
_ = _globalSlots.sharedHandlers.Remove(messageHandler);
|
|
2757
|
+
MarkDirtyHandler(messageHandler);
|
|
2758
|
+
_globalSlotSweepCandidate = true;
|
|
2759
|
+
// Final-removal of this handler from sharedHandlers is the 1 -> 0 transition that
|
|
2760
|
+
// mirrors back into liveCount. Partial deregistration (count > 1) leaves liveCount
|
|
2761
|
+
// alone -- the dictionary entry is still present.
|
|
2762
|
+
_globalSlots.liveCount--;
|
|
2763
|
+
}
|
|
2764
|
+
else
|
|
2765
|
+
{
|
|
2766
|
+
_globalSlots.sharedHandlers[messageHandler] = count - 1;
|
|
2767
|
+
}
|
|
2745
2768
|
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
};
|
|
2769
|
+
StageGlobalDispatchSnapshot<IUntargetedMessage>(
|
|
2770
|
+
this,
|
|
2771
|
+
_globalSlots,
|
|
2772
|
+
DispatchKind.Untargeted
|
|
2773
|
+
);
|
|
2774
|
+
StageGlobalDispatchSnapshot<ITargetedMessage>(
|
|
2775
|
+
this,
|
|
2776
|
+
_globalSlots,
|
|
2777
|
+
DispatchKind.Targeted
|
|
2778
|
+
);
|
|
2779
|
+
StageGlobalDispatchSnapshot<IBroadcastMessage>(
|
|
2780
|
+
this,
|
|
2781
|
+
_globalSlots,
|
|
2782
|
+
DispatchKind.Broadcast
|
|
2783
|
+
);
|
|
2784
|
+
DebugAssertGlobalLiveCount();
|
|
2763
2785
|
}
|
|
2764
2786
|
|
|
2765
2787
|
/// <inheritdoc />
|
|
2766
|
-
public
|
|
2788
|
+
public MessageBusRegistration RegisterUntargetedInterceptor<T>(
|
|
2767
2789
|
UntargetedInterceptor<T> interceptor,
|
|
2768
2790
|
int priority = 0
|
|
2769
2791
|
)
|
|
2770
2792
|
where T : IUntargetedMessage
|
|
2771
2793
|
{
|
|
2772
2794
|
EnsureAotUntargetedBridge<T>();
|
|
2773
|
-
|
|
2795
|
+
long touchTick = AdvanceTick();
|
|
2774
2796
|
InvalidateDispatchPlans();
|
|
2775
2797
|
InterceptorCache<object> prioritizedInterceptors =
|
|
2776
2798
|
_untargetedInterceptsByType.GetOrAdd<T>();
|
|
@@ -2819,107 +2841,29 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2819
2841
|
);
|
|
2820
2842
|
|
|
2821
2843
|
long capturedGeneration = _resetGeneration;
|
|
2822
|
-
return (
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
)
|
|
2835
|
-
)
|
|
2836
|
-
{
|
|
2837
|
-
return;
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
_ = AdvanceTick();
|
|
2841
|
-
InvalidateDispatchPlans();
|
|
2842
|
-
prioritizedInterceptors.lastTouchTicks = _tickCounter;
|
|
2843
|
-
MarkDirtyType<T>();
|
|
2844
|
-
_log.Log(
|
|
2845
|
-
new MessagingRegistration(
|
|
2846
|
-
InstanceId.EmptyId,
|
|
2847
|
-
type,
|
|
2848
|
-
RegistrationType.Deregister,
|
|
2849
|
-
RegistrationMethod.Interceptor
|
|
2850
|
-
)
|
|
2851
|
-
);
|
|
2852
|
-
bool removed = false;
|
|
2853
|
-
if (_uniqueInterceptorsAndPriorities.TryGetValue(interceptor, out priorityCount))
|
|
2854
|
-
{
|
|
2855
|
-
if (priorityCount.TryGetValue(priority, out count))
|
|
2856
|
-
{
|
|
2857
|
-
if (1 < count)
|
|
2858
|
-
{
|
|
2859
|
-
priorityCount[priority] = count - 1;
|
|
2860
|
-
}
|
|
2861
|
-
else
|
|
2862
|
-
{
|
|
2863
|
-
removed = true;
|
|
2864
|
-
_ = priorityCount.Remove(priority);
|
|
2865
|
-
}
|
|
2866
|
-
}
|
|
2867
|
-
|
|
2868
|
-
if (priorityCount.Count == 0)
|
|
2869
|
-
{
|
|
2870
|
-
_uniqueInterceptorsAndPriorities.Remove(interceptor);
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
else if (MessagingDebug.enabled)
|
|
2874
|
-
{
|
|
2875
|
-
MessagingDebug.Log(
|
|
2876
|
-
LogLevel.Error,
|
|
2877
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
2878
|
-
interceptor
|
|
2879
|
-
);
|
|
2880
|
-
}
|
|
2881
|
-
|
|
2882
|
-
bool complete = false;
|
|
2883
|
-
if (removed)
|
|
2884
|
-
{
|
|
2885
|
-
if (_untargetedInterceptsByType.TryGetValue<T>(out prioritizedInterceptors))
|
|
2886
|
-
{
|
|
2887
|
-
if (
|
|
2888
|
-
prioritizedInterceptors.handlers.TryGetValue(
|
|
2889
|
-
priority,
|
|
2890
|
-
out List<object> interceptors
|
|
2891
|
-
)
|
|
2892
|
-
)
|
|
2893
|
-
{
|
|
2894
|
-
complete = interceptors.Remove(interceptor);
|
|
2895
|
-
if (interceptors.Count == 0)
|
|
2896
|
-
{
|
|
2897
|
-
_ = prioritizedInterceptors.handlers.Remove(priority);
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
if (!complete && MessagingDebug.enabled)
|
|
2903
|
-
{
|
|
2904
|
-
MessagingDebug.Log(
|
|
2905
|
-
LogLevel.Error,
|
|
2906
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
2907
|
-
interceptor
|
|
2908
|
-
);
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
};
|
|
2844
|
+
return new MessageBusRegistration(
|
|
2845
|
+
MessageBusRegistration.Kind.UntargetedInterceptor,
|
|
2846
|
+
RegistrationMethod.Interceptor,
|
|
2847
|
+
priority,
|
|
2848
|
+
capturedGeneration,
|
|
2849
|
+
0L,
|
|
2850
|
+
touchTick,
|
|
2851
|
+
capturedInterceptors,
|
|
2852
|
+
null,
|
|
2853
|
+
interceptor,
|
|
2854
|
+
default
|
|
2855
|
+
);
|
|
2912
2856
|
}
|
|
2913
2857
|
|
|
2914
2858
|
/// <inheritdoc />
|
|
2915
|
-
public
|
|
2859
|
+
public MessageBusRegistration RegisterTargetedInterceptor<T>(
|
|
2916
2860
|
TargetedInterceptor<T> interceptor,
|
|
2917
2861
|
int priority = 0
|
|
2918
2862
|
)
|
|
2919
2863
|
where T : ITargetedMessage
|
|
2920
2864
|
{
|
|
2921
2865
|
EnsureAotTargetedBridge<T>();
|
|
2922
|
-
|
|
2866
|
+
long touchTick = AdvanceTick();
|
|
2923
2867
|
InvalidateDispatchPlans();
|
|
2924
2868
|
InterceptorCache<object> prioritizedInterceptors =
|
|
2925
2869
|
_targetedInterceptsByType.GetOrAdd<T>();
|
|
@@ -2968,107 +2912,29 @@ namespace DxMessaging.Core.MessageBus
|
|
|
2968
2912
|
);
|
|
2969
2913
|
|
|
2970
2914
|
long capturedGeneration = _resetGeneration;
|
|
2971
|
-
return (
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
)
|
|
2984
|
-
)
|
|
2985
|
-
{
|
|
2986
|
-
return;
|
|
2987
|
-
}
|
|
2988
|
-
|
|
2989
|
-
_ = AdvanceTick();
|
|
2990
|
-
InvalidateDispatchPlans();
|
|
2991
|
-
prioritizedInterceptors.lastTouchTicks = _tickCounter;
|
|
2992
|
-
MarkDirtyType<T>();
|
|
2993
|
-
_log.Log(
|
|
2994
|
-
new MessagingRegistration(
|
|
2995
|
-
InstanceId.EmptyId,
|
|
2996
|
-
type,
|
|
2997
|
-
RegistrationType.Deregister,
|
|
2998
|
-
RegistrationMethod.Interceptor
|
|
2999
|
-
)
|
|
3000
|
-
);
|
|
3001
|
-
bool removed = false;
|
|
3002
|
-
if (_uniqueInterceptorsAndPriorities.TryGetValue(interceptor, out priorityCount))
|
|
3003
|
-
{
|
|
3004
|
-
if (priorityCount.TryGetValue(priority, out count))
|
|
3005
|
-
{
|
|
3006
|
-
if (1 < count)
|
|
3007
|
-
{
|
|
3008
|
-
priorityCount[priority] = count - 1;
|
|
3009
|
-
}
|
|
3010
|
-
else
|
|
3011
|
-
{
|
|
3012
|
-
removed = true;
|
|
3013
|
-
_ = priorityCount.Remove(priority);
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
|
|
3017
|
-
if (priorityCount.Count == 0)
|
|
3018
|
-
{
|
|
3019
|
-
_uniqueInterceptorsAndPriorities.Remove(interceptor);
|
|
3020
|
-
}
|
|
3021
|
-
}
|
|
3022
|
-
else if (MessagingDebug.enabled)
|
|
3023
|
-
{
|
|
3024
|
-
MessagingDebug.Log(
|
|
3025
|
-
LogLevel.Error,
|
|
3026
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
3027
|
-
interceptor
|
|
3028
|
-
);
|
|
3029
|
-
}
|
|
3030
|
-
|
|
3031
|
-
bool complete = false;
|
|
3032
|
-
if (removed)
|
|
3033
|
-
{
|
|
3034
|
-
if (_targetedInterceptsByType.TryGetValue<T>(out prioritizedInterceptors))
|
|
3035
|
-
{
|
|
3036
|
-
if (
|
|
3037
|
-
prioritizedInterceptors.handlers.TryGetValue(
|
|
3038
|
-
priority,
|
|
3039
|
-
out List<object> interceptors
|
|
3040
|
-
)
|
|
3041
|
-
)
|
|
3042
|
-
{
|
|
3043
|
-
complete = interceptors.Remove(interceptor);
|
|
3044
|
-
if (interceptors.Count == 0)
|
|
3045
|
-
{
|
|
3046
|
-
_ = prioritizedInterceptors.handlers.Remove(priority);
|
|
3047
|
-
}
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
|
|
3051
|
-
if (!complete && MessagingDebug.enabled)
|
|
3052
|
-
{
|
|
3053
|
-
MessagingDebug.Log(
|
|
3054
|
-
LogLevel.Error,
|
|
3055
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
3056
|
-
interceptor
|
|
3057
|
-
);
|
|
3058
|
-
}
|
|
3059
|
-
}
|
|
3060
|
-
};
|
|
2915
|
+
return new MessageBusRegistration(
|
|
2916
|
+
MessageBusRegistration.Kind.TargetedInterceptor,
|
|
2917
|
+
RegistrationMethod.Interceptor,
|
|
2918
|
+
priority,
|
|
2919
|
+
capturedGeneration,
|
|
2920
|
+
0L,
|
|
2921
|
+
touchTick,
|
|
2922
|
+
capturedInterceptors,
|
|
2923
|
+
null,
|
|
2924
|
+
interceptor,
|
|
2925
|
+
default
|
|
2926
|
+
);
|
|
3061
2927
|
}
|
|
3062
2928
|
|
|
3063
2929
|
/// <inheritdoc />
|
|
3064
|
-
public
|
|
2930
|
+
public MessageBusRegistration RegisterBroadcastInterceptor<T>(
|
|
3065
2931
|
BroadcastInterceptor<T> interceptor,
|
|
3066
2932
|
int priority = 0
|
|
3067
2933
|
)
|
|
3068
2934
|
where T : IBroadcastMessage
|
|
3069
2935
|
{
|
|
3070
2936
|
EnsureAotSourcedBridge<T>();
|
|
3071
|
-
|
|
2937
|
+
long touchTick = AdvanceTick();
|
|
3072
2938
|
InvalidateDispatchPlans();
|
|
3073
2939
|
InterceptorCache<object> prioritizedInterceptors =
|
|
3074
2940
|
_broadcastInterceptsByType.GetOrAdd<T>();
|
|
@@ -3117,96 +2983,18 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3117
2983
|
);
|
|
3118
2984
|
|
|
3119
2985
|
long capturedGeneration = _resetGeneration;
|
|
3120
|
-
return (
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
)
|
|
3133
|
-
)
|
|
3134
|
-
{
|
|
3135
|
-
return;
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
|
-
_ = AdvanceTick();
|
|
3139
|
-
InvalidateDispatchPlans();
|
|
3140
|
-
prioritizedInterceptors.lastTouchTicks = _tickCounter;
|
|
3141
|
-
MarkDirtyType<T>();
|
|
3142
|
-
_log.Log(
|
|
3143
|
-
new MessagingRegistration(
|
|
3144
|
-
InstanceId.EmptyId,
|
|
3145
|
-
type,
|
|
3146
|
-
RegistrationType.Deregister,
|
|
3147
|
-
RegistrationMethod.Interceptor
|
|
3148
|
-
)
|
|
3149
|
-
);
|
|
3150
|
-
bool removed = false;
|
|
3151
|
-
if (_uniqueInterceptorsAndPriorities.TryGetValue(interceptor, out priorityCount))
|
|
3152
|
-
{
|
|
3153
|
-
if (priorityCount.TryGetValue(priority, out count))
|
|
3154
|
-
{
|
|
3155
|
-
if (1 < count)
|
|
3156
|
-
{
|
|
3157
|
-
priorityCount[priority] = count - 1;
|
|
3158
|
-
}
|
|
3159
|
-
else
|
|
3160
|
-
{
|
|
3161
|
-
removed = true;
|
|
3162
|
-
_ = priorityCount.Remove(priority);
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
|
|
3166
|
-
if (priorityCount.Count == 0)
|
|
3167
|
-
{
|
|
3168
|
-
_uniqueInterceptorsAndPriorities.Remove(interceptor);
|
|
3169
|
-
}
|
|
3170
|
-
}
|
|
3171
|
-
else if (MessagingDebug.enabled)
|
|
3172
|
-
{
|
|
3173
|
-
MessagingDebug.Log(
|
|
3174
|
-
LogLevel.Error,
|
|
3175
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
3176
|
-
interceptor
|
|
3177
|
-
);
|
|
3178
|
-
}
|
|
3179
|
-
|
|
3180
|
-
bool complete = false;
|
|
3181
|
-
if (removed)
|
|
3182
|
-
{
|
|
3183
|
-
if (_broadcastInterceptsByType.TryGetValue<T>(out prioritizedInterceptors))
|
|
3184
|
-
{
|
|
3185
|
-
if (
|
|
3186
|
-
prioritizedInterceptors.handlers.TryGetValue(
|
|
3187
|
-
priority,
|
|
3188
|
-
out List<object> interceptors
|
|
3189
|
-
)
|
|
3190
|
-
)
|
|
3191
|
-
{
|
|
3192
|
-
complete = interceptors.Remove(interceptor);
|
|
3193
|
-
if (interceptors.Count == 0)
|
|
3194
|
-
{
|
|
3195
|
-
_ = prioritizedInterceptors.handlers.Remove(priority);
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
}
|
|
3199
|
-
|
|
3200
|
-
if (!complete && MessagingDebug.enabled)
|
|
3201
|
-
{
|
|
3202
|
-
MessagingDebug.Log(
|
|
3203
|
-
LogLevel.Error,
|
|
3204
|
-
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
3205
|
-
interceptor
|
|
3206
|
-
);
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
};
|
|
2986
|
+
return new MessageBusRegistration(
|
|
2987
|
+
MessageBusRegistration.Kind.BroadcastInterceptor,
|
|
2988
|
+
RegistrationMethod.Interceptor,
|
|
2989
|
+
priority,
|
|
2990
|
+
capturedGeneration,
|
|
2991
|
+
0L,
|
|
2992
|
+
touchTick,
|
|
2993
|
+
capturedInterceptors,
|
|
2994
|
+
null,
|
|
2995
|
+
interceptor,
|
|
2996
|
+
default
|
|
2997
|
+
);
|
|
3210
2998
|
}
|
|
3211
2999
|
|
|
3212
3000
|
private bool IsStaleInterceptorDeregisterAfterSweep<T>(
|
|
@@ -3221,7 +3009,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3221
3009
|
}
|
|
3222
3010
|
|
|
3223
3011
|
/// <inheritdoc />
|
|
3224
|
-
public
|
|
3012
|
+
public MessageBusRegistration RegisterUntargetedPostProcessor<T>(
|
|
3225
3013
|
MessageHandler messageHandler,
|
|
3226
3014
|
int priority = 0
|
|
3227
3015
|
)
|
|
@@ -3237,7 +3025,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3237
3025
|
}
|
|
3238
3026
|
|
|
3239
3027
|
/// <inheritdoc />
|
|
3240
|
-
public
|
|
3028
|
+
public MessageBusRegistration RegisterTargetedPostProcessor<T>(
|
|
3241
3029
|
InstanceId target,
|
|
3242
3030
|
MessageHandler messageHandler,
|
|
3243
3031
|
int priority = 0
|
|
@@ -3255,7 +3043,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3255
3043
|
}
|
|
3256
3044
|
|
|
3257
3045
|
/// <inheritdoc />
|
|
3258
|
-
public
|
|
3046
|
+
public MessageBusRegistration RegisterTargetedWithoutTargetingPostProcessor<T>(
|
|
3259
3047
|
MessageHandler messageHandler,
|
|
3260
3048
|
int priority = 0
|
|
3261
3049
|
)
|
|
@@ -3271,7 +3059,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3271
3059
|
}
|
|
3272
3060
|
|
|
3273
3061
|
/// <inheritdoc />
|
|
3274
|
-
public
|
|
3062
|
+
public MessageBusRegistration RegisterBroadcastPostProcessor<T>(
|
|
3275
3063
|
InstanceId source,
|
|
3276
3064
|
MessageHandler messageHandler,
|
|
3277
3065
|
int priority = 0
|
|
@@ -3289,7 +3077,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
3289
3077
|
}
|
|
3290
3078
|
|
|
3291
3079
|
/// <inheritdoc />
|
|
3292
|
-
public
|
|
3080
|
+
public MessageBusRegistration RegisterBroadcastWithoutSourcePostProcessor<T>(
|
|
3293
3081
|
MessageHandler messageHandler,
|
|
3294
3082
|
int priority = 0
|
|
3295
3083
|
)
|
|
@@ -5122,7 +4910,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5122
4910
|
return true;
|
|
5123
4911
|
}
|
|
5124
4912
|
|
|
5125
|
-
private
|
|
4913
|
+
private MessageBusRegistration InternalRegisterUntargeted<T>(
|
|
5126
4914
|
MessageHandler messageHandler,
|
|
5127
4915
|
MessageCache<HandlerCache<int, HandlerCache>> sinks,
|
|
5128
4916
|
RegistrationMethod registrationMethod,
|
|
@@ -5182,48 +4970,65 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5182
4970
|
);
|
|
5183
4971
|
|
|
5184
4972
|
long capturedGeneration = _resetGeneration;
|
|
5185
|
-
return (
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
4973
|
+
return new MessageBusRegistration(
|
|
4974
|
+
MessageBusRegistration.Kind.Handler,
|
|
4975
|
+
registrationMethod,
|
|
4976
|
+
priority,
|
|
4977
|
+
capturedGeneration,
|
|
4978
|
+
0L,
|
|
4979
|
+
touchTick,
|
|
4980
|
+
capturedHandlers,
|
|
4981
|
+
null,
|
|
4982
|
+
messageHandler,
|
|
4983
|
+
default
|
|
4984
|
+
);
|
|
4985
|
+
}
|
|
5195
4986
|
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
}
|
|
4987
|
+
/// <summary>
|
|
4988
|
+
/// Re-expression of the former <see cref="InternalRegisterUntargeted{T}"/> closure body:
|
|
4989
|
+
/// the scalar (untargeted / without-context) handler deregistration. Behaviour and the
|
|
4990
|
+
/// four reentrancy invariants are unchanged; the closure's captured locals are read from
|
|
4991
|
+
/// <paramref name="reg"/>'s fields instead, and the sink is re-resolved from the method.
|
|
4992
|
+
/// </summary>
|
|
4993
|
+
private void DeregisterScalarHandler<T>(in MessageBusRegistration reg)
|
|
4994
|
+
where T : IMessage
|
|
4995
|
+
{
|
|
4996
|
+
// Generation guard: if ResetState() ran after this handle was captured (e.g. a
|
|
4997
|
+
// deferred Object.Destroy fires after a domain-reload-style reset), silently no-op
|
|
4998
|
+
// rather than logging a misleading over-deregistration error.
|
|
4999
|
+
if (reg.generation != _resetGeneration)
|
|
5000
|
+
{
|
|
5001
|
+
return;
|
|
5002
|
+
}
|
|
5213
5003
|
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
}
|
|
5004
|
+
MessageHandler messageHandler = (MessageHandler)reg.payload;
|
|
5005
|
+
HandlerCache<int, HandlerCache> capturedHandlers =
|
|
5006
|
+
(HandlerCache<int, HandlerCache>)reg.capturedPrimary;
|
|
5007
|
+
int priority = reg.priority;
|
|
5008
|
+
RegistrationMethod registrationMethod = reg.method;
|
|
5009
|
+
SlotKey slotKey = RegistrationMethodAxes.GetSlotKey(registrationMethod);
|
|
5010
|
+
Type type = typeof(T);
|
|
5011
|
+
InstanceId handlerOwnerId = messageHandler.owner;
|
|
5223
5012
|
|
|
5224
|
-
|
|
5225
|
-
|
|
5013
|
+
long deregisterTouchTick = AdvanceTick();
|
|
5014
|
+
InvalidateDispatchPlans();
|
|
5226
5015
|
|
|
5016
|
+
// FAST PATH: operate on the captured leaf handler-cache (already pinned on the
|
|
5017
|
+
// handle at registration time) DIRECTLY, without re-resolving the sink from the
|
|
5018
|
+
// method (ScalarSinkForMethod) or re-walking sinks->type->priority->handler. When
|
|
5019
|
+
// the generation guard above has passed and the captured bucket still holds this
|
|
5020
|
+
// handler, the captured leaf IS the live sink entry (handles are unique and never
|
|
5021
|
+
// reused), so the re-resolution + ReferenceEquals identity check is redundant. The
|
|
5022
|
+
// sweep-staleness / over-deregistration classification only matters when the handler
|
|
5023
|
+
// is NOT found, so it is deferred to the cold fallback below. This removes the
|
|
5024
|
+
// per-deregistration sink re-resolution (the measured cold-path regression source)
|
|
5025
|
+
// while preserving every guard and the throw-safe ordering (this method performs no
|
|
5026
|
+
// user callback; the throwing IMessageBus.Deregister boundary is the caller's).
|
|
5027
|
+
if (
|
|
5028
|
+
capturedHandlers.handlers.TryGetValue(priority, out HandlerCache cache)
|
|
5029
|
+
&& cache.handlers.TryGetValue(messageHandler, out int count)
|
|
5030
|
+
)
|
|
5031
|
+
{
|
|
5227
5032
|
_log.Log(
|
|
5228
5033
|
new MessagingRegistration(
|
|
5229
5034
|
handlerOwnerId,
|
|
@@ -5232,30 +5037,28 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5232
5037
|
registrationMethod
|
|
5233
5038
|
)
|
|
5234
5039
|
);
|
|
5235
|
-
Touch(
|
|
5236
|
-
|
|
5237
|
-
|
|
5040
|
+
Touch(capturedHandlers, deregisterTouchTick);
|
|
5041
|
+
capturedHandlers.version++;
|
|
5042
|
+
cache.version++;
|
|
5043
|
+
Dictionary<MessageHandler, int> handler = cache.handlers;
|
|
5238
5044
|
if (count <= 1)
|
|
5239
5045
|
{
|
|
5240
|
-
|
|
5241
|
-
// List.Remove is O(n) over the same-priority bucket.
|
|
5242
|
-
//
|
|
5243
|
-
//
|
|
5244
|
-
//
|
|
5245
|
-
//
|
|
5246
|
-
// order, unlike Dictionary enumeration whose freed slots
|
|
5247
|
-
// are reused LIFO. Mirrors the MessageHandler-side
|
|
5046
|
+
_ = handler.Remove(messageHandler);
|
|
5047
|
+
// List.Remove is O(n) over the same-priority bucket. Accepted tradeoff (here
|
|
5048
|
+
// and at the context-path sibling site): buckets are small in practice,
|
|
5049
|
+
// removal is a cold churn path, and the list keeps dispatch-order rebuilds
|
|
5050
|
+
// allocation-free while preserving first-registration order, unlike Dictionary
|
|
5051
|
+
// enumeration whose freed slots are reused LIFO. Mirrors the MessageHandler-side
|
|
5248
5052
|
// insertionOrder tradeoff.
|
|
5249
5053
|
_ = cache.insertionOrder.Remove(messageHandler);
|
|
5250
5054
|
MarkDirtyHandler(messageHandler);
|
|
5251
|
-
cache.version++;
|
|
5252
5055
|
// do not mutate cache.cache here; let next read rebuild from handlers
|
|
5253
5056
|
|
|
5254
5057
|
if (handler.Count == 0)
|
|
5255
5058
|
{
|
|
5256
|
-
_ =
|
|
5059
|
+
_ = capturedHandlers.handlers.Remove(priority);
|
|
5257
5060
|
// remove priority from order
|
|
5258
|
-
List<int> order =
|
|
5061
|
+
List<int> order = capturedHandlers.order;
|
|
5259
5062
|
int removeIdx = order.IndexOf(priority);
|
|
5260
5063
|
if (removeIdx >= 0)
|
|
5261
5064
|
{
|
|
@@ -5263,30 +5066,51 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5263
5066
|
}
|
|
5264
5067
|
}
|
|
5265
5068
|
|
|
5266
|
-
if (
|
|
5069
|
+
if (capturedHandlers.handlers.Count == 0)
|
|
5267
5070
|
{
|
|
5268
5071
|
MarkDirtyType<T>();
|
|
5269
5072
|
}
|
|
5270
|
-
|
|
5271
|
-
if (!complete && MessagingDebug.enabled)
|
|
5272
|
-
{
|
|
5273
|
-
MessagingDebug.Log(
|
|
5274
|
-
LogLevel.Error,
|
|
5275
|
-
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5276
|
-
type,
|
|
5277
|
-
messageHandler
|
|
5278
|
-
);
|
|
5279
|
-
}
|
|
5280
5073
|
}
|
|
5281
5074
|
else
|
|
5282
5075
|
{
|
|
5283
5076
|
handler[messageHandler] = count - 1;
|
|
5284
5077
|
}
|
|
5285
|
-
StageDispatchSnapshot<T>(this,
|
|
5286
|
-
|
|
5078
|
+
StageDispatchSnapshot<T>(this, capturedHandlers, slotKey);
|
|
5079
|
+
return;
|
|
5080
|
+
}
|
|
5081
|
+
|
|
5082
|
+
// COLD FALLBACK: the handler was not found in the captured bucket, so this is a no-op
|
|
5083
|
+
// deregistration (post-sweep, or a genuine over-deregistration) -- nothing is removed,
|
|
5084
|
+
// so NO version bump / snapshot invalidation is performed. Bumping here would
|
|
5085
|
+
// spuriously rebuild whichever bucket currently occupies this priority, which after a
|
|
5086
|
+
// full deregister + re-registration at the same priority is the NEW live bucket (the
|
|
5087
|
+
// stale handle must not touch it). Re-resolve the live sink only to CLASSIFY this as a
|
|
5088
|
+
// silent stale-after-sweep no-op versus a genuine over-deregistration. Rare path; not
|
|
5089
|
+
// on the steady deregistration cost.
|
|
5090
|
+
MessageCache<HandlerCache<int, HandlerCache>> sinks = ScalarSinkForMethod(
|
|
5091
|
+
registrationMethod
|
|
5092
|
+
);
|
|
5093
|
+
_ = sinks.TryGetValue<T>(out HandlerCache<int, HandlerCache> handlers);
|
|
5094
|
+
if (
|
|
5095
|
+
capturedHandlers.handlers.Count == 0
|
|
5096
|
+
&& !ReferenceEquals(handlers, capturedHandlers)
|
|
5097
|
+
)
|
|
5098
|
+
{
|
|
5099
|
+
return;
|
|
5100
|
+
}
|
|
5101
|
+
|
|
5102
|
+
if (MessagingDebug.enabled)
|
|
5103
|
+
{
|
|
5104
|
+
MessagingDebug.Log(
|
|
5105
|
+
LogLevel.Error,
|
|
5106
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5107
|
+
type,
|
|
5108
|
+
messageHandler
|
|
5109
|
+
);
|
|
5110
|
+
}
|
|
5287
5111
|
}
|
|
5288
5112
|
|
|
5289
|
-
private
|
|
5113
|
+
private MessageBusRegistration InternalRegisterWithContext<T>(
|
|
5290
5114
|
InstanceId context,
|
|
5291
5115
|
MessageHandler messageHandler,
|
|
5292
5116
|
MessageCache<Dictionary<InstanceId, HandlerCache<int, HandlerCache>>> sinks,
|
|
@@ -5362,45 +5186,59 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5362
5186
|
StageDispatchSnapshot<T>(this, handlers, slotKey);
|
|
5363
5187
|
|
|
5364
5188
|
long capturedGeneration = _resetGeneration;
|
|
5365
|
-
return (
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5189
|
+
return new MessageBusRegistration(
|
|
5190
|
+
MessageBusRegistration.Kind.Handler,
|
|
5191
|
+
registrationMethod,
|
|
5192
|
+
priority,
|
|
5193
|
+
capturedGeneration,
|
|
5194
|
+
0L,
|
|
5195
|
+
touchTick,
|
|
5196
|
+
capturedHandlers,
|
|
5197
|
+
capturedBroadcastHandlers,
|
|
5198
|
+
messageHandler,
|
|
5199
|
+
context
|
|
5200
|
+
);
|
|
5201
|
+
}
|
|
5373
5202
|
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
}
|
|
5203
|
+
/// <summary>
|
|
5204
|
+
/// Re-expression of the former <see cref="InternalRegisterWithContext{T}"/> closure body:
|
|
5205
|
+
/// the keyed (targeted / sourced-broadcast) handler deregistration. Behaviour and the four
|
|
5206
|
+
/// reentrancy invariants are unchanged; the closure's captured locals are read from
|
|
5207
|
+
/// <paramref name="reg"/>'s fields, and the sink is re-resolved from the method.
|
|
5208
|
+
/// </summary>
|
|
5209
|
+
private void DeregisterContextHandler<T>(in MessageBusRegistration reg)
|
|
5210
|
+
where T : IMessage
|
|
5211
|
+
{
|
|
5212
|
+
// Generation guard: see DeregisterScalarHandler for the rationale. Skip silently when
|
|
5213
|
+
// the handle outlived a Reset.
|
|
5214
|
+
if (reg.generation != _resetGeneration)
|
|
5215
|
+
{
|
|
5216
|
+
return;
|
|
5217
|
+
}
|
|
5390
5218
|
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
}
|
|
5219
|
+
MessageHandler messageHandler = (MessageHandler)reg.payload;
|
|
5220
|
+
HandlerCache<int, HandlerCache> capturedHandlers =
|
|
5221
|
+
(HandlerCache<int, HandlerCache>)reg.capturedPrimary;
|
|
5222
|
+
InstanceId context = reg.context;
|
|
5223
|
+
int priority = reg.priority;
|
|
5224
|
+
RegistrationMethod registrationMethod = reg.method;
|
|
5225
|
+
SlotKey slotKey = RegistrationMethodAxes.GetSlotKey(registrationMethod);
|
|
5226
|
+
Type type = typeof(T);
|
|
5400
5227
|
|
|
5401
|
-
|
|
5402
|
-
|
|
5228
|
+
long deregisterTouchTick = AdvanceTick();
|
|
5229
|
+
InvalidateDispatchPlans();
|
|
5403
5230
|
|
|
5231
|
+
// FAST PATH: operate on the captured per-context leaf handler-cache directly, without
|
|
5232
|
+
// re-resolving the sink (ContextSinkForMethod) or re-walking sinks->type->context->
|
|
5233
|
+
// priority->handler. See DeregisterScalarHandler for the full rationale and the
|
|
5234
|
+
// sweep-staleness argument (the context sweep, like the scalar sweep, only evicts
|
|
5235
|
+
// EMPTY caches, so a found handler is never in a swept/detached cache). Throw-safe:
|
|
5236
|
+
// no user callback runs here.
|
|
5237
|
+
if (
|
|
5238
|
+
capturedHandlers.handlers.TryGetValue(priority, out HandlerCache cache)
|
|
5239
|
+
&& cache.handlers.TryGetValue(messageHandler, out int count)
|
|
5240
|
+
)
|
|
5241
|
+
{
|
|
5404
5242
|
_log.Log(
|
|
5405
5243
|
new MessagingRegistration(
|
|
5406
5244
|
context,
|
|
@@ -5409,23 +5247,23 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5409
5247
|
registrationMethod
|
|
5410
5248
|
)
|
|
5411
5249
|
);
|
|
5412
|
-
Touch(
|
|
5413
|
-
|
|
5250
|
+
Touch(capturedHandlers, deregisterTouchTick);
|
|
5251
|
+
cache.version++;
|
|
5252
|
+
Dictionary<MessageHandler, int> handler = cache.handlers;
|
|
5414
5253
|
if (count <= 1)
|
|
5415
5254
|
{
|
|
5416
|
-
|
|
5417
|
-
// O(n) List.Remove: see the tradeoff comment at the
|
|
5418
|
-
//
|
|
5255
|
+
_ = handler.Remove(messageHandler);
|
|
5256
|
+
// O(n) List.Remove: see the tradeoff comment at the scalar-path sibling site in
|
|
5257
|
+
// DeregisterScalarHandler.
|
|
5419
5258
|
_ = cache.insertionOrder.Remove(messageHandler);
|
|
5420
5259
|
MarkDirtyHandler(messageHandler);
|
|
5421
|
-
cache.version++;
|
|
5422
5260
|
// do not mutate cache.cache here; let next read rebuild from handlers
|
|
5423
5261
|
if (handler.Count == 0)
|
|
5424
5262
|
{
|
|
5425
|
-
|
|
5426
|
-
_ =
|
|
5263
|
+
capturedHandlers.version++;
|
|
5264
|
+
_ = capturedHandlers.handlers.Remove(priority);
|
|
5427
5265
|
// remove priority from order
|
|
5428
|
-
List<int> order =
|
|
5266
|
+
List<int> order = capturedHandlers.order;
|
|
5429
5267
|
int removeIdx = order.IndexOf(priority);
|
|
5430
5268
|
if (removeIdx >= 0)
|
|
5431
5269
|
{
|
|
@@ -5433,29 +5271,265 @@ namespace DxMessaging.Core.MessageBus
|
|
|
5433
5271
|
}
|
|
5434
5272
|
}
|
|
5435
5273
|
|
|
5436
|
-
if (
|
|
5274
|
+
if (capturedHandlers.handlers.Count == 0)
|
|
5437
5275
|
{
|
|
5438
5276
|
MarkDirtyTarget<T>(context);
|
|
5439
5277
|
}
|
|
5440
|
-
|
|
5441
|
-
if (!complete && MessagingDebug.enabled)
|
|
5442
|
-
{
|
|
5443
|
-
MessagingDebug.Log(
|
|
5444
|
-
LogLevel.Error,
|
|
5445
|
-
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5446
|
-
type,
|
|
5447
|
-
messageHandler
|
|
5448
|
-
);
|
|
5449
|
-
}
|
|
5450
5278
|
}
|
|
5451
5279
|
else
|
|
5452
5280
|
{
|
|
5453
5281
|
handler[messageHandler] = count - 1;
|
|
5454
5282
|
}
|
|
5455
|
-
StageDispatchSnapshot<T>(this,
|
|
5283
|
+
StageDispatchSnapshot<T>(this, capturedHandlers, slotKey);
|
|
5284
|
+
return;
|
|
5285
|
+
}
|
|
5286
|
+
|
|
5287
|
+
// COLD FALLBACK: handler not found in the captured bucket -> a no-op deregistration
|
|
5288
|
+
// (nothing removed), so NO version bump is performed (it would spuriously rebuild the
|
|
5289
|
+
// bucket currently at this priority -- the NEW live bucket after a full deregister +
|
|
5290
|
+
// re-registration). Re-resolve only to CLASSIFY stale-after-sweep (silent) versus
|
|
5291
|
+
// over-deregistration (error). Rare path; not on the steady deregistration cost.
|
|
5292
|
+
MessageCache<Dictionary<InstanceId, HandlerCache<int, HandlerCache>>> sinks =
|
|
5293
|
+
ContextSinkForMethod(registrationMethod);
|
|
5294
|
+
if (IsStaleContextDeregisterAfterSweep<T>(sinks, context, capturedHandlers))
|
|
5295
|
+
{
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5298
|
+
|
|
5299
|
+
if (MessagingDebug.enabled)
|
|
5300
|
+
{
|
|
5301
|
+
MessagingDebug.Log(
|
|
5302
|
+
LogLevel.Error,
|
|
5303
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5304
|
+
type,
|
|
5305
|
+
messageHandler
|
|
5306
|
+
);
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
/// <inheritdoc />
|
|
5311
|
+
public void Deregister<T>(in MessageBusRegistration registration)
|
|
5312
|
+
where T : IMessage
|
|
5313
|
+
{
|
|
5314
|
+
switch (registration.kind)
|
|
5315
|
+
{
|
|
5316
|
+
case MessageBusRegistration.Kind.Handler:
|
|
5317
|
+
if (IsContextMethod(registration.method))
|
|
5318
|
+
{
|
|
5319
|
+
DeregisterContextHandler<T>(in registration);
|
|
5320
|
+
}
|
|
5321
|
+
else
|
|
5322
|
+
{
|
|
5323
|
+
DeregisterScalarHandler<T>(in registration);
|
|
5324
|
+
}
|
|
5325
|
+
break;
|
|
5326
|
+
case MessageBusRegistration.Kind.UntargetedInterceptor:
|
|
5327
|
+
case MessageBusRegistration.Kind.TargetedInterceptor:
|
|
5328
|
+
case MessageBusRegistration.Kind.BroadcastInterceptor:
|
|
5329
|
+
DeregisterInterceptor<T>(in registration);
|
|
5330
|
+
break;
|
|
5331
|
+
case MessageBusRegistration.Kind.GlobalAcceptAll:
|
|
5332
|
+
DeregisterGlobalAcceptAll(in registration);
|
|
5333
|
+
break;
|
|
5334
|
+
default:
|
|
5335
|
+
// Kind.None is the empty/sentinel handle (no-op); Kind.External handles are
|
|
5336
|
+
// minted by a foreign IMessageBus implementation and own no store here.
|
|
5337
|
+
break;
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
|
|
5341
|
+
/// <summary>
|
|
5342
|
+
/// Re-expression of the former interceptor closure body. The interceptor store is selected
|
|
5343
|
+
/// by <see cref="MessageBusRegistration.kind"/> (all three interceptor registrars log the
|
|
5344
|
+
/// single <see cref="RegistrationMethod.Interceptor"/>, so the method cannot discriminate).
|
|
5345
|
+
/// </summary>
|
|
5346
|
+
private void DeregisterInterceptor<T>(in MessageBusRegistration reg)
|
|
5347
|
+
where T : IMessage
|
|
5348
|
+
{
|
|
5349
|
+
// Generation guard: see DeregisterScalarHandler.
|
|
5350
|
+
if (reg.generation != _resetGeneration)
|
|
5351
|
+
{
|
|
5352
|
+
return;
|
|
5353
|
+
}
|
|
5354
|
+
|
|
5355
|
+
MessageCache<InterceptorCache<object>> interceptsByType = reg.kind switch
|
|
5356
|
+
{
|
|
5357
|
+
MessageBusRegistration.Kind.UntargetedInterceptor => _untargetedInterceptsByType,
|
|
5358
|
+
MessageBusRegistration.Kind.TargetedInterceptor => _targetedInterceptsByType,
|
|
5359
|
+
MessageBusRegistration.Kind.BroadcastInterceptor => _broadcastInterceptsByType,
|
|
5360
|
+
_ => null,
|
|
5456
5361
|
};
|
|
5362
|
+
if (interceptsByType == null)
|
|
5363
|
+
{
|
|
5364
|
+
return;
|
|
5365
|
+
}
|
|
5366
|
+
|
|
5367
|
+
InterceptorCache<object> capturedInterceptors =
|
|
5368
|
+
(InterceptorCache<object>)reg.capturedPrimary;
|
|
5369
|
+
object interceptor = reg.payload;
|
|
5370
|
+
int priority = reg.priority;
|
|
5371
|
+
|
|
5372
|
+
if (IsStaleInterceptorDeregisterAfterSweep<T>(interceptsByType, capturedInterceptors))
|
|
5373
|
+
{
|
|
5374
|
+
return;
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
_ = AdvanceTick();
|
|
5378
|
+
InvalidateDispatchPlans();
|
|
5379
|
+
capturedInterceptors.lastTouchTicks = _tickCounter;
|
|
5380
|
+
MarkDirtyType<T>();
|
|
5381
|
+
_log.Log(
|
|
5382
|
+
new MessagingRegistration(
|
|
5383
|
+
InstanceId.EmptyId,
|
|
5384
|
+
typeof(T),
|
|
5385
|
+
RegistrationType.Deregister,
|
|
5386
|
+
RegistrationMethod.Interceptor
|
|
5387
|
+
)
|
|
5388
|
+
);
|
|
5389
|
+
bool removed = false;
|
|
5390
|
+
if (
|
|
5391
|
+
_uniqueInterceptorsAndPriorities.TryGetValue(
|
|
5392
|
+
interceptor,
|
|
5393
|
+
out Dictionary<int, int> priorityCount
|
|
5394
|
+
)
|
|
5395
|
+
)
|
|
5396
|
+
{
|
|
5397
|
+
if (priorityCount.TryGetValue(priority, out int count))
|
|
5398
|
+
{
|
|
5399
|
+
if (1 < count)
|
|
5400
|
+
{
|
|
5401
|
+
priorityCount[priority] = count - 1;
|
|
5402
|
+
}
|
|
5403
|
+
else
|
|
5404
|
+
{
|
|
5405
|
+
removed = true;
|
|
5406
|
+
_ = priorityCount.Remove(priority);
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
|
|
5410
|
+
if (priorityCount.Count == 0)
|
|
5411
|
+
{
|
|
5412
|
+
_uniqueInterceptorsAndPriorities.Remove(interceptor);
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
else if (MessagingDebug.enabled)
|
|
5416
|
+
{
|
|
5417
|
+
MessagingDebug.Log(
|
|
5418
|
+
LogLevel.Error,
|
|
5419
|
+
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5420
|
+
interceptor
|
|
5421
|
+
);
|
|
5422
|
+
}
|
|
5423
|
+
|
|
5424
|
+
bool complete = false;
|
|
5425
|
+
if (removed)
|
|
5426
|
+
{
|
|
5427
|
+
if (
|
|
5428
|
+
interceptsByType.TryGetValue<T>(
|
|
5429
|
+
out InterceptorCache<object> prioritizedInterceptors
|
|
5430
|
+
)
|
|
5431
|
+
)
|
|
5432
|
+
{
|
|
5433
|
+
if (
|
|
5434
|
+
prioritizedInterceptors.handlers.TryGetValue(
|
|
5435
|
+
priority,
|
|
5436
|
+
out List<object> interceptors
|
|
5437
|
+
)
|
|
5438
|
+
)
|
|
5439
|
+
{
|
|
5440
|
+
complete = interceptors.Remove(interceptor);
|
|
5441
|
+
if (interceptors.Count == 0)
|
|
5442
|
+
{
|
|
5443
|
+
_ = prioritizedInterceptors.handlers.Remove(priority);
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
|
|
5448
|
+
if (!complete && MessagingDebug.enabled)
|
|
5449
|
+
{
|
|
5450
|
+
MessagingDebug.Log(
|
|
5451
|
+
LogLevel.Error,
|
|
5452
|
+
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
5453
|
+
interceptor
|
|
5454
|
+
);
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
5457
|
}
|
|
5458
5458
|
|
|
5459
|
+
/// <summary>
|
|
5460
|
+
/// True for the keyed (targeted / sourced-broadcast) handler registration methods, whose
|
|
5461
|
+
/// deregistration runs <see cref="DeregisterContextHandler{T}"/>; false for the scalar
|
|
5462
|
+
/// (untargeted / without-context) methods. Mirrors the register-side sink routing.
|
|
5463
|
+
/// </summary>
|
|
5464
|
+
private static bool IsContextMethod(RegistrationMethod method) =>
|
|
5465
|
+
method switch
|
|
5466
|
+
{
|
|
5467
|
+
RegistrationMethod.Targeted
|
|
5468
|
+
or RegistrationMethod.Broadcast
|
|
5469
|
+
or RegistrationMethod.TargetedPostProcessor
|
|
5470
|
+
or RegistrationMethod.BroadcastPostProcessor => true,
|
|
5471
|
+
_ => false,
|
|
5472
|
+
};
|
|
5473
|
+
|
|
5474
|
+
/// <summary>
|
|
5475
|
+
/// Reverse of the register-side hardcoded scalar-sink selection (e.g.
|
|
5476
|
+
/// <c>_scalarSinks[BusSinkIndex.UntargetedHandleDefault]</c>): maps a scalar handler method
|
|
5477
|
+
/// back to its sink so <see cref="DeregisterScalarHandler{T}"/> can re-resolve it.
|
|
5478
|
+
/// </summary>
|
|
5479
|
+
private MessageCache<HandlerCache<int, HandlerCache>> ScalarSinkForMethod(
|
|
5480
|
+
RegistrationMethod method
|
|
5481
|
+
) =>
|
|
5482
|
+
method switch
|
|
5483
|
+
{
|
|
5484
|
+
RegistrationMethod.Untargeted => _scalarSinks[BusSinkIndex.UntargetedHandleDefault],
|
|
5485
|
+
RegistrationMethod.BroadcastWithoutSource => _scalarSinks[
|
|
5486
|
+
BusSinkIndex.BroadcastHandleWithoutContext
|
|
5487
|
+
],
|
|
5488
|
+
RegistrationMethod.TargetedWithoutTargeting => _scalarSinks[
|
|
5489
|
+
BusSinkIndex.TargetedHandleWithoutContext
|
|
5490
|
+
],
|
|
5491
|
+
RegistrationMethod.UntargetedPostProcessor => _scalarSinks[
|
|
5492
|
+
BusSinkIndex.UntargetedPostProcessDefault
|
|
5493
|
+
],
|
|
5494
|
+
RegistrationMethod.TargetedWithoutTargetingPostProcessor => _scalarSinks[
|
|
5495
|
+
BusSinkIndex.TargetedPostProcessWithoutContext
|
|
5496
|
+
],
|
|
5497
|
+
RegistrationMethod.BroadcastWithoutSourcePostProcessor => _scalarSinks[
|
|
5498
|
+
BusSinkIndex.BroadcastPostProcessWithoutContext
|
|
5499
|
+
],
|
|
5500
|
+
_ => throw new ArgumentOutOfRangeException(
|
|
5501
|
+
nameof(method),
|
|
5502
|
+
method,
|
|
5503
|
+
"Not a scalar handler registration method."
|
|
5504
|
+
),
|
|
5505
|
+
};
|
|
5506
|
+
|
|
5507
|
+
/// <summary>
|
|
5508
|
+
/// Reverse of the register-side hardcoded context-sink selection: maps a keyed handler
|
|
5509
|
+
/// method back to its sink so <see cref="DeregisterContextHandler{T}"/> can re-resolve it.
|
|
5510
|
+
/// </summary>
|
|
5511
|
+
private MessageCache<
|
|
5512
|
+
Dictionary<InstanceId, HandlerCache<int, HandlerCache>>
|
|
5513
|
+
> ContextSinkForMethod(RegistrationMethod method) =>
|
|
5514
|
+
method switch
|
|
5515
|
+
{
|
|
5516
|
+
RegistrationMethod.Targeted => _contextSinks[BusContextIndex.TargetedHandleDefault],
|
|
5517
|
+
RegistrationMethod.Broadcast => _contextSinks[
|
|
5518
|
+
BusContextIndex.BroadcastHandleDefault
|
|
5519
|
+
],
|
|
5520
|
+
RegistrationMethod.TargetedPostProcessor => _contextSinks[
|
|
5521
|
+
BusContextIndex.TargetedPostProcessDefault
|
|
5522
|
+
],
|
|
5523
|
+
RegistrationMethod.BroadcastPostProcessor => _contextSinks[
|
|
5524
|
+
BusContextIndex.BroadcastPostProcessDefault
|
|
5525
|
+
],
|
|
5526
|
+
_ => throw new ArgumentOutOfRangeException(
|
|
5527
|
+
nameof(method),
|
|
5528
|
+
method,
|
|
5529
|
+
"Not a context handler registration method."
|
|
5530
|
+
),
|
|
5531
|
+
};
|
|
5532
|
+
|
|
5459
5533
|
private static bool IsStaleContextDeregisterAfterSweep<T>(
|
|
5460
5534
|
MessageCache<Dictionary<InstanceId, HandlerCache<int, HandlerCache>>> sinks,
|
|
5461
5535
|
InstanceId context,
|