com.wallstop-studios.dxmessaging 3.0.1 → 3.1.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 +211 -2
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs +69 -62
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +3 -3
- package/Editor/Analyzers/System.Collections.Immutable.dll.meta +3 -3
- package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +3 -3
- package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +3 -3
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +15 -2
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +2 -2
- package/Editor/AssemblyInfo.cs.meta +9 -1
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs +24 -15
- package/Editor/CustomEditors/MessagingComponentEditor.cs.meta +9 -1
- package/Editor/DxMessagingEditorIdle.cs +62 -0
- package/{Runtime/Core/Internal/TypedDispatchLinkIndex.cs.meta → Editor/DxMessagingEditorIdle.cs.meta} +1 -1
- package/Editor/DxMessagingEditorInitializer.cs +112 -15
- package/Editor/DxMessagingEditorInitializer.cs.meta +9 -1
- package/Editor/DxMessagingEditorLog.cs +32 -0
- package/Editor/DxMessagingEditorLog.cs.meta +11 -0
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +135 -12
- package/Editor/Settings/DxMessagingSettings.cs +92 -31
- package/Editor/Settings/DxMessagingSettings.cs.meta +9 -1
- package/Editor/Settings/DxMessagingSettingsProvider.cs.meta +9 -1
- package/Editor/SetupCscRsp.cs +339 -173
- package/Editor/SetupCscRsp.cs.meta +9 -1
- package/Editor/Testing/MessagingComponentEditorHarness.cs +1 -1
- package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +9 -1
- package/README.md +17 -18
- package/Runtime/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs.meta +9 -1
- package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs.meta +9 -1
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +2 -4
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs.meta +9 -1
- package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs.meta +9 -1
- package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs.meta +9 -1
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs +56 -0
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs.meta +11 -0
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +44 -26
- package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +9 -1
- package/Runtime/Core/Diagnostics/MessageEmissionData.cs.meta +9 -1
- package/Runtime/Core/Diagnostics/MessageRegistrationData.cs.meta +9 -1
- package/Runtime/Core/Diagnostics/MessageRegistrationType.cs.meta +9 -1
- package/Runtime/Core/Extensions/EnumExtensions.cs +6 -5
- package/Runtime/Core/Extensions/EnumExtensions.cs.meta +9 -1
- package/Runtime/Core/Extensions/IListExtensions.cs.meta +9 -1
- package/Runtime/Core/Extensions/MessageExtensions.cs +0 -60
- package/Runtime/Core/Helper/MessageCache.cs.meta +9 -1
- package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +9 -1
- package/Runtime/Core/InstanceId.cs +25 -1
- package/Runtime/Core/Internal/DxUnsafe.cs +60 -0
- package/Runtime/Core/Internal/DxUnsafe.cs.meta +11 -0
- package/Runtime/Core/Internal/FlatDispatch.cs +198 -0
- package/Runtime/Core/Internal/FlatDispatch.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedSlots.cs +5 -21
- package/Runtime/Core/MessageBus/IMessageBus.cs +12 -12
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +1 -0
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs +7 -6
- package/Runtime/Core/MessageBus/MessageBus.cs +2313 -2936
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +187 -14
- package/Runtime/Core/MessageHandler.cs +1023 -1143
- package/Runtime/Core/MessageRegistrationToken.cs +425 -47
- package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +9 -1
- package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +9 -1
- package/Runtime/Core/Messages/StringMessage.cs.meta +9 -1
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/MessageAwareComponent.cs +46 -1
- package/Runtime/Unity/MessagingComponent.cs +43 -10
- package/Runtime/WallstopStudios.DxMessaging.asmdef +1 -1
- package/Samples~/DI/README.md +7 -7
- package/SourceGenerators/Directory.Build.props +50 -3
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +96 -63
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +745 -87
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +9 -1
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +39 -46
- package/SourceGenerators/global.json +7 -0
- package/SourceGenerators/global.json.meta +7 -0
- package/package.json +27 -40
- package/Runtime/Core/Internal/TypedDispatchLinkIndex.cs +0 -51
|
@@ -37,413 +37,6 @@ namespace DxMessaging.Core
|
|
|
37
37
|
IComparable,
|
|
38
38
|
IComparable<MessageHandler>
|
|
39
39
|
{
|
|
40
|
-
private static void PrefreezePriorityCache<TMessage, THandler>(
|
|
41
|
-
TypedHandler<TMessage> handler,
|
|
42
|
-
int slotIndex,
|
|
43
|
-
int priority,
|
|
44
|
-
long emissionId
|
|
45
|
-
)
|
|
46
|
-
where TMessage : IMessage
|
|
47
|
-
{
|
|
48
|
-
Dictionary<int, IHandlerActionCache> byPriority = handler.GetPriorityHandlers(
|
|
49
|
-
slotIndex
|
|
50
|
-
);
|
|
51
|
-
if (
|
|
52
|
-
byPriority != null
|
|
53
|
-
&& byPriority.TryGetValue(priority, out IHandlerActionCache erasedCache)
|
|
54
|
-
&& erasedCache is HandlerActionCache<THandler> cache
|
|
55
|
-
)
|
|
56
|
-
{
|
|
57
|
-
_ = TypedHandler<TMessage>.GetOrAddNewHandlerStack(cache, emissionId);
|
|
58
|
-
cache.prefreezeInvocationCount++;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private static void PrefreezeContextCache<TMessage, THandler>(
|
|
63
|
-
TypedHandler<TMessage> handler,
|
|
64
|
-
int slotIndex,
|
|
65
|
-
InstanceId context,
|
|
66
|
-
int priority,
|
|
67
|
-
long emissionId
|
|
68
|
-
)
|
|
69
|
-
where TMessage : IMessage
|
|
70
|
-
{
|
|
71
|
-
Dictionary<InstanceId, Dictionary<int, IHandlerActionCache>> byContext =
|
|
72
|
-
handler.GetContextHandlers(slotIndex);
|
|
73
|
-
if (
|
|
74
|
-
byContext != null
|
|
75
|
-
&& byContext.TryGetValue(
|
|
76
|
-
context,
|
|
77
|
-
out Dictionary<int, IHandlerActionCache> byPriority
|
|
78
|
-
)
|
|
79
|
-
&& byPriority.TryGetValue(priority, out IHandlerActionCache erasedCache)
|
|
80
|
-
&& erasedCache is HandlerActionCache<THandler> cache
|
|
81
|
-
)
|
|
82
|
-
{
|
|
83
|
-
_ = TypedHandler<TMessage>.GetOrAddNewHandlerStack(cache, emissionId);
|
|
84
|
-
cache.prefreezeInvocationCount++;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private static int GetPriorityPrefreezeInvocationCount<TMessage, THandler>(
|
|
89
|
-
TypedHandler<TMessage> handler,
|
|
90
|
-
int slotIndex,
|
|
91
|
-
int priority
|
|
92
|
-
)
|
|
93
|
-
where TMessage : IMessage
|
|
94
|
-
{
|
|
95
|
-
Dictionary<int, IHandlerActionCache> byPriority = handler.GetPriorityHandlers(
|
|
96
|
-
slotIndex
|
|
97
|
-
);
|
|
98
|
-
if (
|
|
99
|
-
byPriority != null
|
|
100
|
-
&& byPriority.TryGetValue(priority, out IHandlerActionCache erasedCache)
|
|
101
|
-
&& erasedCache is HandlerActionCache<THandler> cache
|
|
102
|
-
)
|
|
103
|
-
{
|
|
104
|
-
return cache.prefreezeInvocationCount;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/// <summary>
|
|
111
|
-
/// Pre-freezes this handler's broadcast post-processor caches for the given message type, source, and priority
|
|
112
|
-
/// for the specified emission id, so registrations during the same emission are not observed.
|
|
113
|
-
/// </summary>
|
|
114
|
-
/// <typeparam name="T">Broadcast message type.</typeparam>
|
|
115
|
-
/// <param name="source">Source instance id.</param>
|
|
116
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
117
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
118
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
119
|
-
internal void PrefreezeBroadcastPostProcessorsForEmission<T>(
|
|
120
|
-
InstanceId source,
|
|
121
|
-
int priority,
|
|
122
|
-
long emissionId,
|
|
123
|
-
IMessageBus messageBus
|
|
124
|
-
)
|
|
125
|
-
where T : IBroadcastMessage
|
|
126
|
-
{
|
|
127
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
128
|
-
{
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
PrefreezeContextCache<T, FastHandler<T>>(
|
|
133
|
-
handler,
|
|
134
|
-
TypedSlotIndex.BroadcastPostProcessFast,
|
|
135
|
-
source,
|
|
136
|
-
priority,
|
|
137
|
-
emissionId
|
|
138
|
-
);
|
|
139
|
-
PrefreezeContextCache<T, Action<T>>(
|
|
140
|
-
handler,
|
|
141
|
-
TypedSlotIndex.BroadcastPostProcessDefault,
|
|
142
|
-
source,
|
|
143
|
-
priority,
|
|
144
|
-
emissionId
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/// <summary>
|
|
149
|
-
/// Pre-freezes this handler's targeted post-processor caches for the given message type, target, and priority
|
|
150
|
-
/// for the specified emission id, so registrations during the same emission are not observed.
|
|
151
|
-
/// </summary>
|
|
152
|
-
/// <typeparam name="T">Targeted message type.</typeparam>
|
|
153
|
-
/// <param name="target">Target instance id.</param>
|
|
154
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
155
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
156
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
157
|
-
internal void PrefreezeTargetedPostProcessorsForEmission<T>(
|
|
158
|
-
InstanceId target,
|
|
159
|
-
int priority,
|
|
160
|
-
long emissionId,
|
|
161
|
-
IMessageBus messageBus
|
|
162
|
-
)
|
|
163
|
-
where T : ITargetedMessage
|
|
164
|
-
{
|
|
165
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
166
|
-
{
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
PrefreezeContextCache<T, FastHandler<T>>(
|
|
171
|
-
handler,
|
|
172
|
-
TypedSlotIndex.TargetedPostProcessFast,
|
|
173
|
-
target,
|
|
174
|
-
priority,
|
|
175
|
-
emissionId
|
|
176
|
-
);
|
|
177
|
-
PrefreezeContextCache<T, Action<T>>(
|
|
178
|
-
handler,
|
|
179
|
-
TypedSlotIndex.TargetedPostProcessDefault,
|
|
180
|
-
target,
|
|
181
|
-
priority,
|
|
182
|
-
emissionId
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/// <summary>
|
|
187
|
-
/// Pre-freezes this handler's targeted-without-targeting handler caches for the given message type and priority
|
|
188
|
-
/// so that removals/additions during the same emission are not observed.
|
|
189
|
-
/// </summary>
|
|
190
|
-
internal void PrefreezeTargetedWithoutTargetingHandlersForEmission<T>(
|
|
191
|
-
int priority,
|
|
192
|
-
long emissionId,
|
|
193
|
-
IMessageBus messageBus
|
|
194
|
-
)
|
|
195
|
-
where T : ITargetedMessage
|
|
196
|
-
{
|
|
197
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
198
|
-
{
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
PrefreezePriorityCache<T, FastHandlerWithContext<T>>(
|
|
203
|
-
handler,
|
|
204
|
-
TypedSlotIndex.TargetedHandleWithoutContextFast,
|
|
205
|
-
priority,
|
|
206
|
-
emissionId
|
|
207
|
-
);
|
|
208
|
-
PrefreezePriorityCache<T, Action<InstanceId, T>>(
|
|
209
|
-
handler,
|
|
210
|
-
TypedSlotIndex.TargetedHandleWithoutContext,
|
|
211
|
-
priority,
|
|
212
|
-
emissionId
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/// <summary>
|
|
217
|
-
/// Pre-freezes this handler's targeted-without-targeting post-processor caches for a given priority.
|
|
218
|
-
/// </summary>
|
|
219
|
-
internal void PrefreezeTargetedWithoutTargetingPostProcessorsForEmission<T>(
|
|
220
|
-
int priority,
|
|
221
|
-
long emissionId,
|
|
222
|
-
IMessageBus messageBus
|
|
223
|
-
)
|
|
224
|
-
where T : ITargetedMessage
|
|
225
|
-
{
|
|
226
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
227
|
-
{
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
PrefreezePriorityCache<T, FastHandlerWithContext<T>>(
|
|
232
|
-
handler,
|
|
233
|
-
TypedSlotIndex.TargetedPostProcessWithoutContextFast,
|
|
234
|
-
priority,
|
|
235
|
-
emissionId
|
|
236
|
-
);
|
|
237
|
-
PrefreezePriorityCache<T, Action<InstanceId, T>>(
|
|
238
|
-
handler,
|
|
239
|
-
TypedSlotIndex.TargetedPostProcessWithoutContext,
|
|
240
|
-
priority,
|
|
241
|
-
emissionId
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/// <summary>
|
|
246
|
-
/// Pre-freezes this handler's untargeted post-processor caches for a given priority.
|
|
247
|
-
/// </summary>
|
|
248
|
-
internal void PrefreezeUntargetedPostProcessorsForEmission<T>(
|
|
249
|
-
int priority,
|
|
250
|
-
long emissionId,
|
|
251
|
-
IMessageBus messageBus
|
|
252
|
-
)
|
|
253
|
-
where T : IUntargetedMessage
|
|
254
|
-
{
|
|
255
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
256
|
-
{
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
PrefreezePriorityCache<T, FastHandler<T>>(
|
|
261
|
-
handler,
|
|
262
|
-
TypedSlotIndex.UntargetedPostProcessFast,
|
|
263
|
-
priority,
|
|
264
|
-
emissionId
|
|
265
|
-
);
|
|
266
|
-
PrefreezePriorityCache<T, Action<T>>(
|
|
267
|
-
handler,
|
|
268
|
-
TypedSlotIndex.UntargetedPostProcessDefault,
|
|
269
|
-
priority,
|
|
270
|
-
emissionId
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/// <summary>
|
|
275
|
-
/// Pre-freezes this handler's broadcast-without-source post-processor caches for a given priority.
|
|
276
|
-
/// </summary>
|
|
277
|
-
internal void PrefreezeBroadcastWithoutSourcePostProcessorsForEmission<T>(
|
|
278
|
-
int priority,
|
|
279
|
-
long emissionId,
|
|
280
|
-
IMessageBus messageBus
|
|
281
|
-
)
|
|
282
|
-
where T : IBroadcastMessage
|
|
283
|
-
{
|
|
284
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
285
|
-
{
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
PrefreezePriorityCache<T, FastHandlerWithContext<T>>(
|
|
290
|
-
handler,
|
|
291
|
-
TypedSlotIndex.BroadcastPostProcessWithoutContextFast,
|
|
292
|
-
priority,
|
|
293
|
-
emissionId
|
|
294
|
-
);
|
|
295
|
-
PrefreezePriorityCache<T, Action<InstanceId, T>>(
|
|
296
|
-
handler,
|
|
297
|
-
TypedSlotIndex.BroadcastPostProcessWithoutContext,
|
|
298
|
-
priority,
|
|
299
|
-
emissionId
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/// <summary>
|
|
304
|
-
/// Pre-freezes this handler's broadcast-without-source handler caches for the given message type and priority
|
|
305
|
-
/// for the specified emission id, so removals during the same emission are not observed.
|
|
306
|
-
/// </summary>
|
|
307
|
-
/// <typeparam name="T">Broadcast message type.</typeparam>
|
|
308
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
309
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
310
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
311
|
-
internal void PrefreezeBroadcastWithoutSourceHandlersForEmission<T>(
|
|
312
|
-
int priority,
|
|
313
|
-
long emissionId,
|
|
314
|
-
IMessageBus messageBus
|
|
315
|
-
)
|
|
316
|
-
where T : IBroadcastMessage
|
|
317
|
-
{
|
|
318
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
319
|
-
{
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
PrefreezePriorityCache<T, FastHandlerWithContext<T>>(
|
|
324
|
-
handler,
|
|
325
|
-
TypedSlotIndex.BroadcastHandleWithoutContextFast,
|
|
326
|
-
priority,
|
|
327
|
-
emissionId
|
|
328
|
-
);
|
|
329
|
-
PrefreezePriorityCache<T, Action<InstanceId, T>>(
|
|
330
|
-
handler,
|
|
331
|
-
TypedSlotIndex.BroadcastHandleWithoutContext,
|
|
332
|
-
priority,
|
|
333
|
-
emissionId
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/// <summary>
|
|
338
|
-
/// Pre-freezes this handler's untargeted handler caches for the given message type and priority
|
|
339
|
-
/// for the specified emission id, so removals during the same emission are not observed.
|
|
340
|
-
/// </summary>
|
|
341
|
-
/// <typeparam name="T">Untargeted message type.</typeparam>
|
|
342
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
343
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
344
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
345
|
-
internal void PrefreezeUntargetedHandlersForEmission<T>(
|
|
346
|
-
int priority,
|
|
347
|
-
long emissionId,
|
|
348
|
-
IMessageBus messageBus
|
|
349
|
-
)
|
|
350
|
-
where T : IUntargetedMessage
|
|
351
|
-
{
|
|
352
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
353
|
-
{
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
PrefreezePriorityCache<T, FastHandler<T>>(
|
|
358
|
-
handler,
|
|
359
|
-
TypedSlotIndex.UntargetedHandleFast,
|
|
360
|
-
priority,
|
|
361
|
-
emissionId
|
|
362
|
-
);
|
|
363
|
-
PrefreezePriorityCache<T, Action<T>>(
|
|
364
|
-
handler,
|
|
365
|
-
TypedSlotIndex.UntargetedHandleDefault,
|
|
366
|
-
priority,
|
|
367
|
-
emissionId
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/// <summary>
|
|
372
|
-
/// Pre-freezes this handler's targeted handler caches for the given message type, target, and priority
|
|
373
|
-
/// for the specified emission id, so removals during the same emission are not observed.
|
|
374
|
-
/// </summary>
|
|
375
|
-
/// <typeparam name="T">Targeted message type.</typeparam>
|
|
376
|
-
/// <param name="target">Target instance id.</param>
|
|
377
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
378
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
379
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
380
|
-
internal void PrefreezeTargetedHandlersForEmission<T>(
|
|
381
|
-
InstanceId target,
|
|
382
|
-
int priority,
|
|
383
|
-
long emissionId,
|
|
384
|
-
IMessageBus messageBus
|
|
385
|
-
)
|
|
386
|
-
where T : ITargetedMessage
|
|
387
|
-
{
|
|
388
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
389
|
-
{
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
PrefreezeContextCache<T, FastHandler<T>>(
|
|
394
|
-
handler,
|
|
395
|
-
TypedSlotIndex.TargetedHandleFast,
|
|
396
|
-
target,
|
|
397
|
-
priority,
|
|
398
|
-
emissionId
|
|
399
|
-
);
|
|
400
|
-
PrefreezeContextCache<T, Action<T>>(
|
|
401
|
-
handler,
|
|
402
|
-
TypedSlotIndex.TargetedHandleDefault,
|
|
403
|
-
target,
|
|
404
|
-
priority,
|
|
405
|
-
emissionId
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/// <summary>
|
|
410
|
-
/// Pre-freezes this handler's broadcast handler caches for the given message type, source, and priority
|
|
411
|
-
/// for the specified emission id, so removals during the same emission are not observed.
|
|
412
|
-
/// </summary>
|
|
413
|
-
/// <typeparam name="T">Broadcast message type.</typeparam>
|
|
414
|
-
/// <param name="source">Source instance id.</param>
|
|
415
|
-
/// <param name="priority">Priority bucket to freeze.</param>
|
|
416
|
-
/// <param name="emissionId">Current emission id.</param>
|
|
417
|
-
/// <param name="messageBus">Bus whose typed handler mapping to use.</param>
|
|
418
|
-
internal void PrefreezeBroadcastHandlersForEmission<T>(
|
|
419
|
-
InstanceId source,
|
|
420
|
-
int priority,
|
|
421
|
-
long emissionId,
|
|
422
|
-
IMessageBus messageBus
|
|
423
|
-
)
|
|
424
|
-
where T : IBroadcastMessage
|
|
425
|
-
{
|
|
426
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T> handler))
|
|
427
|
-
{
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
PrefreezeContextCache<T, FastHandler<T>>(
|
|
432
|
-
handler,
|
|
433
|
-
TypedSlotIndex.BroadcastHandleFast,
|
|
434
|
-
source,
|
|
435
|
-
priority,
|
|
436
|
-
emissionId
|
|
437
|
-
);
|
|
438
|
-
PrefreezeContextCache<T, Action<T>>(
|
|
439
|
-
handler,
|
|
440
|
-
TypedSlotIndex.BroadcastHandleDefault,
|
|
441
|
-
source,
|
|
442
|
-
priority,
|
|
443
|
-
emissionId
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
40
|
/// <summary>
|
|
448
41
|
/// High-performance handler that receives the message by reference (no boxing/copies).
|
|
449
42
|
/// </summary>
|
|
@@ -2092,7 +1685,7 @@ namespace DxMessaging.Core
|
|
|
2092
1685
|
MessageCache<object> handlersByType = _handlersByTypeByMessageBus[messageBusIndex];
|
|
2093
1686
|
if (handlersByType.TryGetValue<T>(out object untypedHandler))
|
|
2094
1687
|
{
|
|
2095
|
-
return
|
|
1688
|
+
return DxUnsafe.As<TypedHandler<T>>(untypedHandler);
|
|
2096
1689
|
}
|
|
2097
1690
|
|
|
2098
1691
|
TypedHandler<T> typedHandler = new();
|
|
@@ -2124,7 +1717,7 @@ namespace DxMessaging.Core
|
|
|
2124
1717
|
.TryGetValue<T>(out object untypedHandler)
|
|
2125
1718
|
)
|
|
2126
1719
|
{
|
|
2127
|
-
existingTypedHandler =
|
|
1720
|
+
existingTypedHandler = DxUnsafe.As<TypedHandler<T>>(untypedHandler);
|
|
2128
1721
|
return true;
|
|
2129
1722
|
}
|
|
2130
1723
|
|
|
@@ -2230,601 +1823,538 @@ namespace DxMessaging.Core
|
|
|
2230
1823
|
return false;
|
|
2231
1824
|
}
|
|
2232
1825
|
|
|
2233
|
-
|
|
1826
|
+
/// <summary>
|
|
1827
|
+
/// Counts the flat-dispatch entries this handler contributes to a
|
|
1828
|
+
/// non-context-keyed slot (untargeted handle/post) at the given
|
|
1829
|
+
/// priority: one entry per unique registered delegate (fast plus
|
|
1830
|
+
/// default). Build-time only; called by MessageBus.BuildFlatDispatch.
|
|
1831
|
+
/// </summary>
|
|
1832
|
+
internal int CountFlatHandlers<T>(
|
|
2234
1833
|
IMessageBus messageBus,
|
|
2235
|
-
int priority
|
|
1834
|
+
int priority,
|
|
1835
|
+
int fastIndex,
|
|
1836
|
+
int defaultIndex
|
|
2236
1837
|
)
|
|
2237
1838
|
where T : IMessage
|
|
2238
1839
|
{
|
|
2239
|
-
if (!GetHandlerForType(messageBus, out TypedHandler<T>
|
|
1840
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
2240
1841
|
{
|
|
2241
1842
|
return 0;
|
|
2242
1843
|
}
|
|
2243
1844
|
|
|
2244
|
-
return
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
1845
|
+
return CountFlatDelegates<FastHandler<T>>(
|
|
1846
|
+
typedHandler.GetPriorityHandlers(fastIndex),
|
|
1847
|
+
priority
|
|
1848
|
+
)
|
|
1849
|
+
+ CountFlatDelegates<Action<T>>(
|
|
1850
|
+
typedHandler.GetPriorityHandlers(defaultIndex),
|
|
1851
|
+
priority
|
|
1852
|
+
);
|
|
2249
1853
|
}
|
|
2250
1854
|
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
1855
|
+
/// <summary>
|
|
1856
|
+
/// Counts the flat-dispatch entries this handler contributes to a
|
|
1857
|
+
/// context-keyed slot (Default-variant targeted/broadcast handle/post)
|
|
1858
|
+
/// for the given context and priority. Build-time only.
|
|
1859
|
+
/// </summary>
|
|
1860
|
+
internal int CountContextFlatHandlers<T>(
|
|
1861
|
+
IMessageBus messageBus,
|
|
1862
|
+
InstanceId context,
|
|
1863
|
+
int priority,
|
|
1864
|
+
int fastIndex,
|
|
1865
|
+
int defaultIndex
|
|
2254
1866
|
)
|
|
2255
1867
|
where T : IMessage
|
|
2256
1868
|
{
|
|
2257
|
-
TypedHandler<T> typedHandler
|
|
2258
|
-
|
|
1869
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
1870
|
+
{
|
|
1871
|
+
return 0;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
return CountFlatDelegates<FastHandler<T>>(
|
|
1875
|
+
GetContextPriorityHandlers(typedHandler, fastIndex, context),
|
|
1876
|
+
priority
|
|
1877
|
+
)
|
|
1878
|
+
+ CountFlatDelegates<Action<T>>(
|
|
1879
|
+
GetContextPriorityHandlers(typedHandler, defaultIndex, context),
|
|
1880
|
+
priority
|
|
1881
|
+
);
|
|
2259
1882
|
}
|
|
2260
1883
|
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
1884
|
+
/// <summary>
|
|
1885
|
+
/// Counts the flat-dispatch entries this handler contributes to a
|
|
1886
|
+
/// WithoutContext targeted/broadcast slot (whose delegates receive the
|
|
1887
|
+
/// routing InstanceId) at the given priority. Build-time only.
|
|
1888
|
+
/// </summary>
|
|
1889
|
+
internal int CountWithContextFlatHandlers<T>(
|
|
1890
|
+
IMessageBus messageBus,
|
|
1891
|
+
int priority,
|
|
1892
|
+
int fastIndex,
|
|
1893
|
+
int defaultIndex
|
|
2264
1894
|
)
|
|
2265
1895
|
where T : IMessage
|
|
2266
1896
|
{
|
|
2267
|
-
TypedHandler<T> typedHandler
|
|
2268
|
-
|
|
2269
|
-
|
|
1897
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
1898
|
+
{
|
|
1899
|
+
return 0;
|
|
1900
|
+
}
|
|
2270
1901
|
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
1902
|
+
return CountFlatDelegates<FastHandlerWithContext<T>>(
|
|
1903
|
+
typedHandler.GetPriorityHandlers(fastIndex),
|
|
1904
|
+
priority
|
|
1905
|
+
)
|
|
1906
|
+
+ CountFlatDelegates<Action<InstanceId, T>>(
|
|
1907
|
+
typedHandler.GetPriorityHandlers(defaultIndex),
|
|
1908
|
+
priority
|
|
1909
|
+
);
|
|
2277
1910
|
}
|
|
2278
1911
|
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
1912
|
+
/// <summary>
|
|
1913
|
+
/// Writes this handler's resolved flat-dispatch entries for a
|
|
1914
|
+
/// non-context-keyed FastHandler-shaped slot into
|
|
1915
|
+
/// <paramref name="target"/> starting at <paramref name="writeIndex"/>:
|
|
1916
|
+
/// all fast entries in registration order, then all default entries in
|
|
1917
|
+
/// registration order, matching the legacy link path's
|
|
1918
|
+
/// fast-before-default contract. Fast entries resolve to the augmented
|
|
1919
|
+
/// FastHandler delegate itself; default entries resolve to the
|
|
1920
|
+
/// FastHandler adapter created at registration time
|
|
1921
|
+
/// (Entry.flatInvoker), so this method allocates nothing.
|
|
1922
|
+
/// Returns the next write index.
|
|
1923
|
+
/// </summary>
|
|
1924
|
+
internal int FillFlatHandlers<T>(
|
|
1925
|
+
IMessageBus messageBus,
|
|
1926
|
+
int priority,
|
|
1927
|
+
int fastIndex,
|
|
1928
|
+
int defaultIndex,
|
|
1929
|
+
FlatDispatchEntry<T>[] target,
|
|
1930
|
+
int writeIndex
|
|
2282
1931
|
)
|
|
2283
1932
|
where T : IMessage
|
|
2284
1933
|
{
|
|
2285
|
-
TypedHandler<T> typedHandler
|
|
2286
|
-
|
|
2287
|
-
|
|
1934
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
1935
|
+
{
|
|
1936
|
+
return writeIndex;
|
|
1937
|
+
}
|
|
2288
1938
|
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
1939
|
+
writeIndex = FillFastFlatEntries(
|
|
1940
|
+
typedHandler.GetPriorityHandlers(fastIndex),
|
|
1941
|
+
priority,
|
|
1942
|
+
target,
|
|
1943
|
+
writeIndex
|
|
1944
|
+
);
|
|
1945
|
+
return FillDefaultFlatEntries(
|
|
1946
|
+
typedHandler.GetPriorityHandlers(defaultIndex),
|
|
1947
|
+
priority,
|
|
1948
|
+
target,
|
|
1949
|
+
writeIndex
|
|
1950
|
+
);
|
|
2297
1951
|
}
|
|
2298
1952
|
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
1953
|
+
/// <summary>
|
|
1954
|
+
/// Context-keyed sibling of <see cref="FillFlatHandlers{T}"/> for the
|
|
1955
|
+
/// Default-variant targeted/broadcast slots: resolves the per-context
|
|
1956
|
+
/// priority map first, then fills fast entries followed by default
|
|
1957
|
+
/// entries in registration order. Returns the next write index.
|
|
1958
|
+
/// </summary>
|
|
1959
|
+
internal int FillContextFlatHandlers<T>(
|
|
1960
|
+
IMessageBus messageBus,
|
|
1961
|
+
InstanceId context,
|
|
1962
|
+
int priority,
|
|
1963
|
+
int fastIndex,
|
|
1964
|
+
int defaultIndex,
|
|
1965
|
+
FlatDispatchEntry<T>[] target,
|
|
1966
|
+
int writeIndex
|
|
2302
1967
|
)
|
|
2303
1968
|
where T : IMessage
|
|
2304
1969
|
{
|
|
2305
|
-
TypedHandler<T> typedHandler
|
|
2306
|
-
|
|
2307
|
-
|
|
1970
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
1971
|
+
{
|
|
1972
|
+
return writeIndex;
|
|
1973
|
+
}
|
|
2308
1974
|
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
1975
|
+
writeIndex = FillFastFlatEntries(
|
|
1976
|
+
GetContextPriorityHandlers(typedHandler, fastIndex, context),
|
|
1977
|
+
priority,
|
|
1978
|
+
target,
|
|
1979
|
+
writeIndex
|
|
1980
|
+
);
|
|
1981
|
+
return FillDefaultFlatEntries(
|
|
1982
|
+
GetContextPriorityHandlers(typedHandler, defaultIndex, context),
|
|
1983
|
+
priority,
|
|
1984
|
+
target,
|
|
1985
|
+
writeIndex
|
|
1986
|
+
);
|
|
2317
1987
|
}
|
|
2318
1988
|
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
1989
|
+
/// <summary>
|
|
1990
|
+
/// WithoutContext sibling of <see cref="FillFlatHandlers{T}"/> for the
|
|
1991
|
+
/// targeted/broadcast slots whose delegates receive the routing
|
|
1992
|
+
/// InstanceId: fills fast (FastHandlerWithContext) entries followed by
|
|
1993
|
+
/// default (Action<InstanceId, T>, via the registration-time
|
|
1994
|
+
/// FastHandlerWithContext adapter) entries in registration order.
|
|
1995
|
+
/// Returns the next write index.
|
|
1996
|
+
/// </summary>
|
|
1997
|
+
internal int FillWithContextFlatHandlers<T>(
|
|
1998
|
+
IMessageBus messageBus,
|
|
1999
|
+
int priority,
|
|
2000
|
+
int fastIndex,
|
|
2001
|
+
int defaultIndex,
|
|
2002
|
+
ContextFlatDispatchEntry<T>[] target,
|
|
2003
|
+
int writeIndex
|
|
2322
2004
|
)
|
|
2323
2005
|
where T : IMessage
|
|
2324
2006
|
{
|
|
2325
|
-
TypedHandler<T> typedHandler
|
|
2326
|
-
|
|
2327
|
-
|
|
2007
|
+
if (!GetHandlerForType(messageBus, out TypedHandler<T> typedHandler))
|
|
2008
|
+
{
|
|
2009
|
+
return writeIndex;
|
|
2010
|
+
}
|
|
2328
2011
|
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2012
|
+
writeIndex = FillFastWithContextFlatEntries(
|
|
2013
|
+
typedHandler.GetPriorityHandlers(fastIndex),
|
|
2014
|
+
priority,
|
|
2015
|
+
target,
|
|
2016
|
+
writeIndex
|
|
2017
|
+
);
|
|
2018
|
+
return FillDefaultWithContextFlatEntries(
|
|
2019
|
+
typedHandler.GetPriorityHandlers(defaultIndex),
|
|
2020
|
+
priority,
|
|
2021
|
+
target,
|
|
2022
|
+
writeIndex
|
|
2023
|
+
);
|
|
2337
2024
|
}
|
|
2338
2025
|
|
|
2339
2026
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2340
|
-
|
|
2341
|
-
|
|
2027
|
+
private static Dictionary<int, IHandlerActionCache> GetContextPriorityHandlers<T>(
|
|
2028
|
+
TypedHandler<T> typedHandler,
|
|
2029
|
+
int slotIndex,
|
|
2030
|
+
InstanceId context
|
|
2342
2031
|
)
|
|
2343
2032
|
where T : IMessage
|
|
2344
2033
|
{
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
// Tests/Editor/Contract/ReflectionHelpers.cs::CloseNestedGeneric.
|
|
2355
|
-
internal readonly struct Entry
|
|
2356
|
-
{
|
|
2357
|
-
/// <summary>
|
|
2358
|
-
/// Initializes an entry used to track handler invocation counts.
|
|
2359
|
-
/// </summary>
|
|
2360
|
-
/// <param name="handler">Handler delegate being tracked.</param>
|
|
2361
|
-
/// <param name="count">Number of times the handler has been cached.</param>
|
|
2362
|
-
public Entry(T handler, int count)
|
|
2363
|
-
{
|
|
2364
|
-
this.handler = handler;
|
|
2365
|
-
this.count = count;
|
|
2366
|
-
}
|
|
2367
|
-
|
|
2368
|
-
public readonly T handler;
|
|
2369
|
-
public readonly int count;
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
|
-
public readonly Dictionary<T, Entry> entries = new();
|
|
2373
|
-
public readonly List<T> cache = new();
|
|
2374
|
-
public long version;
|
|
2375
|
-
public long lastSeenVersion = -1;
|
|
2376
|
-
public long lastSeenEmissionId = -1;
|
|
2377
|
-
internal int prefreezeInvocationCount;
|
|
2378
|
-
|
|
2379
|
-
/// <summary>Monotonic version field, read-only on the interface surface.</summary>
|
|
2380
|
-
long DxMessaging.Core.Internal.IHandlerActionCache.Version
|
|
2381
|
-
{
|
|
2382
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2383
|
-
get => version;
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
/// <summary>Most recent dispatcher-observed version; mutable through the staged dispatch path.</summary>
|
|
2387
|
-
long DxMessaging.Core.Internal.IHandlerActionCache.LastSeenVersion
|
|
2388
|
-
{
|
|
2389
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2390
|
-
get => lastSeenVersion;
|
|
2391
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2392
|
-
set => lastSeenVersion = value;
|
|
2393
|
-
}
|
|
2394
|
-
|
|
2395
|
-
/// <summary>Most recent dispatcher-observed bus emission id.</summary>
|
|
2396
|
-
long DxMessaging.Core.Internal.IHandlerActionCache.LastSeenEmissionId
|
|
2397
|
-
{
|
|
2398
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2399
|
-
get => lastSeenEmissionId;
|
|
2400
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2401
|
-
set => lastSeenEmissionId = value;
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
/// <summary>Prefreeze invocation counter mirror; maintained by the dispatchers.</summary>
|
|
2405
|
-
int DxMessaging.Core.Internal.IHandlerActionCache.PrefreezeInvocationCount
|
|
2406
|
-
{
|
|
2407
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2408
|
-
get => prefreezeInvocationCount;
|
|
2409
|
-
}
|
|
2410
|
-
|
|
2411
|
-
/// <summary>True iff the entries dictionary holds zero handlers.</summary>
|
|
2412
|
-
bool DxMessaging.Core.Internal.IHandlerActionCache.IsEmpty
|
|
2034
|
+
Dictionary<InstanceId, Dictionary<int, IHandlerActionCache>> byContext =
|
|
2035
|
+
typedHandler.GetContextHandlers(slotIndex);
|
|
2036
|
+
if (
|
|
2037
|
+
byContext != null
|
|
2038
|
+
&& byContext.TryGetValue(
|
|
2039
|
+
context,
|
|
2040
|
+
out Dictionary<int, IHandlerActionCache> byPriority
|
|
2041
|
+
)
|
|
2042
|
+
)
|
|
2413
2043
|
{
|
|
2414
|
-
|
|
2415
|
-
get => entries.Count == 0;
|
|
2044
|
+
return byPriority;
|
|
2416
2045
|
}
|
|
2417
2046
|
|
|
2418
|
-
|
|
2419
|
-
/// Eviction-driven full clear; bumps <see cref="version"/> as the LAST step
|
|
2420
|
-
/// so captured dispatch closures observe invalidation.
|
|
2421
|
-
/// </summary>
|
|
2422
|
-
void DxMessaging.Core.Internal.IHandlerActionCache.Reset()
|
|
2423
|
-
{
|
|
2424
|
-
entries.Clear();
|
|
2425
|
-
cache.Clear();
|
|
2426
|
-
lastSeenVersion = -1;
|
|
2427
|
-
lastSeenEmissionId = -1;
|
|
2428
|
-
prefreezeInvocationCount = 0;
|
|
2429
|
-
unchecked
|
|
2430
|
-
{
|
|
2431
|
-
++version;
|
|
2432
|
-
}
|
|
2433
|
-
}
|
|
2047
|
+
return null;
|
|
2434
2048
|
}
|
|
2435
2049
|
|
|
2436
|
-
|
|
2437
|
-
|
|
2050
|
+
private static int CountFlatDelegates<TDelegate>(
|
|
2051
|
+
Dictionary<int, IHandlerActionCache> byPriority,
|
|
2052
|
+
int priority
|
|
2053
|
+
)
|
|
2438
2054
|
{
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
{
|
|
2444
|
-
this.typedHandler = typedHandler;
|
|
2445
|
-
this.capturedGeneration = capturedGeneration;
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2449
|
-
internal void Invoke(
|
|
2450
|
-
MessageHandler messageHandler,
|
|
2451
|
-
ref T message,
|
|
2452
|
-
int priority,
|
|
2453
|
-
long emissionId
|
|
2055
|
+
if (
|
|
2056
|
+
byPriority != null
|
|
2057
|
+
&& byPriority.TryGetValue(priority, out IHandlerActionCache erased)
|
|
2058
|
+
&& erased is HandlerActionCache<TDelegate> cache
|
|
2454
2059
|
)
|
|
2455
2060
|
{
|
|
2456
|
-
|
|
2457
|
-
// Sits at the top of Invoke so reclaimed wrappers return before handler-slot
|
|
2458
|
-
// walks when the outer wrapper has been reclaimed.
|
|
2459
|
-
if (typedHandler._outerGeneration != capturedGeneration)
|
|
2460
|
-
{
|
|
2461
|
-
return;
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
|
-
if (!messageHandler.active)
|
|
2465
|
-
{
|
|
2466
|
-
return;
|
|
2467
|
-
}
|
|
2468
|
-
|
|
2469
|
-
typedHandler.HandleUntargeted(ref message, priority, emissionId);
|
|
2061
|
+
return cache.insertionOrder.Count;
|
|
2470
2062
|
}
|
|
2063
|
+
|
|
2064
|
+
return 0;
|
|
2471
2065
|
}
|
|
2472
2066
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2067
|
+
private int FillFastFlatEntries<T>(
|
|
2068
|
+
Dictionary<int, IHandlerActionCache> byPriority,
|
|
2069
|
+
int priority,
|
|
2070
|
+
FlatDispatchEntry<T>[] target,
|
|
2071
|
+
int writeIndex
|
|
2072
|
+
)
|
|
2073
|
+
where T : IMessage
|
|
2475
2074
|
{
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
TypedHandler<TMessage> typedHandler,
|
|
2481
|
-
long capturedGeneration
|
|
2075
|
+
if (
|
|
2076
|
+
byPriority == null
|
|
2077
|
+
|| !byPriority.TryGetValue(priority, out IHandlerActionCache erased)
|
|
2078
|
+
|| erased is not HandlerActionCache<FastHandler<T>> cache
|
|
2482
2079
|
)
|
|
2483
2080
|
{
|
|
2484
|
-
|
|
2485
|
-
this.capturedGeneration = capturedGeneration;
|
|
2081
|
+
return writeIndex;
|
|
2486
2082
|
}
|
|
2487
2083
|
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
ref TMessage message,
|
|
2492
|
-
int priority,
|
|
2493
|
-
long emissionId
|
|
2494
|
-
)
|
|
2084
|
+
List<FastHandler<T>> ordered = cache.insertionOrder;
|
|
2085
|
+
int orderedCount = ordered.Count;
|
|
2086
|
+
for (int i = 0; i < orderedCount; ++i)
|
|
2495
2087
|
{
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
if (!messageHandler.active)
|
|
2088
|
+
if (
|
|
2089
|
+
cache.entries.TryGetValue(
|
|
2090
|
+
ordered[i],
|
|
2091
|
+
out HandlerActionCache<FastHandler<T>>.Entry entry
|
|
2092
|
+
)
|
|
2093
|
+
)
|
|
2505
2094
|
{
|
|
2506
|
-
|
|
2095
|
+
target[writeIndex++] = new FlatDispatchEntry<T>(this, entry.handler);
|
|
2507
2096
|
}
|
|
2508
|
-
|
|
2509
|
-
typedHandler.HandleUntargetedPostProcessing(ref message, priority, emissionId);
|
|
2510
2097
|
}
|
|
2098
|
+
|
|
2099
|
+
return writeIndex;
|
|
2511
2100
|
}
|
|
2512
2101
|
|
|
2513
|
-
|
|
2514
|
-
|
|
2102
|
+
private int FillDefaultFlatEntries<T>(
|
|
2103
|
+
Dictionary<int, IHandlerActionCache> byPriority,
|
|
2104
|
+
int priority,
|
|
2105
|
+
FlatDispatchEntry<T>[] target,
|
|
2106
|
+
int writeIndex
|
|
2107
|
+
)
|
|
2108
|
+
where T : IMessage
|
|
2515
2109
|
{
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
TypedHandler<TMessage> typedHandler,
|
|
2521
|
-
long capturedGeneration
|
|
2110
|
+
if (
|
|
2111
|
+
byPriority == null
|
|
2112
|
+
|| !byPriority.TryGetValue(priority, out IHandlerActionCache erased)
|
|
2113
|
+
|| erased is not HandlerActionCache<Action<T>> cache
|
|
2522
2114
|
)
|
|
2523
2115
|
{
|
|
2524
|
-
|
|
2525
|
-
this.capturedGeneration = capturedGeneration;
|
|
2116
|
+
return writeIndex;
|
|
2526
2117
|
}
|
|
2527
2118
|
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
ref InstanceId target,
|
|
2532
|
-
ref TMessage message,
|
|
2533
|
-
int priority,
|
|
2534
|
-
long emissionId
|
|
2535
|
-
)
|
|
2119
|
+
List<Action<T>> ordered = cache.insertionOrder;
|
|
2120
|
+
int orderedCount = ordered.Count;
|
|
2121
|
+
for (int i = 0; i < orderedCount; ++i)
|
|
2536
2122
|
{
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2123
|
+
if (
|
|
2124
|
+
!cache.entries.TryGetValue(
|
|
2125
|
+
ordered[i],
|
|
2126
|
+
out HandlerActionCache<Action<T>>.Entry entry
|
|
2127
|
+
)
|
|
2128
|
+
)
|
|
2541
2129
|
{
|
|
2542
|
-
|
|
2130
|
+
continue;
|
|
2543
2131
|
}
|
|
2544
2132
|
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
private readonly TypedHandler<TMessage> typedHandler;
|
|
2553
|
-
internal readonly long capturedGeneration;
|
|
2554
|
-
|
|
2555
|
-
internal TargetedPostDispatchLink(
|
|
2556
|
-
TypedHandler<TMessage> typedHandler,
|
|
2557
|
-
long capturedGeneration
|
|
2558
|
-
)
|
|
2559
|
-
{
|
|
2560
|
-
this.typedHandler = typedHandler;
|
|
2561
|
-
this.capturedGeneration = capturedGeneration;
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2565
|
-
internal void Invoke(
|
|
2566
|
-
MessageHandler messageHandler,
|
|
2567
|
-
ref InstanceId target,
|
|
2568
|
-
ref TMessage message,
|
|
2569
|
-
int priority,
|
|
2570
|
-
long emissionId
|
|
2571
|
-
)
|
|
2572
|
-
{
|
|
2573
|
-
// Generation guard: 1 field read + 1 compare per dispatch on the hot path.
|
|
2574
|
-
// Sits at the top of Invoke so reclaimed wrappers return before handler-slot
|
|
2575
|
-
// walks when the outer wrapper has been reclaimed.
|
|
2576
|
-
if (typedHandler._outerGeneration != capturedGeneration)
|
|
2133
|
+
// Every default registration path for the flattened slots
|
|
2134
|
+
// supplies the adapter at registration time (AddUntargetedHandler,
|
|
2135
|
+
// AddTargetedHandler, AddSourcedBroadcastHandler, and their
|
|
2136
|
+
// post-processor siblings). The type test doubles as a null
|
|
2137
|
+
// guard; a missing adapter would indicate a new registration
|
|
2138
|
+
// path that forgot to provide one.
|
|
2139
|
+
if (entry.flatInvoker is FastHandler<T> invoker)
|
|
2577
2140
|
{
|
|
2578
|
-
|
|
2141
|
+
target[writeIndex++] = new FlatDispatchEntry<T>(this, invoker);
|
|
2579
2142
|
}
|
|
2580
|
-
|
|
2581
|
-
typedHandler.HandleTargetedPostProcessing(
|
|
2582
|
-
ref target,
|
|
2583
|
-
ref message,
|
|
2584
|
-
priority,
|
|
2585
|
-
emissionId
|
|
2586
|
-
);
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
|
|
2590
|
-
internal sealed class TargetedWithoutTargetingDispatchLink<TMessage>
|
|
2591
|
-
where TMessage : IMessage
|
|
2592
|
-
{
|
|
2593
|
-
private readonly TypedHandler<TMessage> typedHandler;
|
|
2594
|
-
internal readonly long capturedGeneration;
|
|
2595
|
-
|
|
2596
|
-
internal TargetedWithoutTargetingDispatchLink(
|
|
2597
|
-
TypedHandler<TMessage> typedHandler,
|
|
2598
|
-
long capturedGeneration
|
|
2599
|
-
)
|
|
2600
|
-
{
|
|
2601
|
-
this.typedHandler = typedHandler;
|
|
2602
|
-
this.capturedGeneration = capturedGeneration;
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2606
|
-
internal void Invoke(
|
|
2607
|
-
MessageHandler messageHandler,
|
|
2608
|
-
ref InstanceId target,
|
|
2609
|
-
ref TMessage message,
|
|
2610
|
-
int priority,
|
|
2611
|
-
long emissionId
|
|
2612
|
-
)
|
|
2613
|
-
{
|
|
2614
|
-
// Generation guard: 1 field read + 1 compare per dispatch on the hot path.
|
|
2615
|
-
// Sits at the top of Invoke so reclaimed wrappers return before handler-slot
|
|
2616
|
-
// walks when the outer wrapper has been reclaimed.
|
|
2617
|
-
if (typedHandler._outerGeneration != capturedGeneration)
|
|
2143
|
+
else
|
|
2618
2144
|
{
|
|
2619
|
-
|
|
2145
|
+
System.Diagnostics.Debug.Assert(
|
|
2146
|
+
false,
|
|
2147
|
+
"Default registration is missing its FastHandler flat invoker; "
|
|
2148
|
+
+ "every Add*Handler/Add*PostProcessor default path must adapt "
|
|
2149
|
+
+ "the augmented handler at registration time."
|
|
2150
|
+
);
|
|
2620
2151
|
}
|
|
2621
|
-
|
|
2622
|
-
typedHandler.HandleTargetedWithoutTargeting(
|
|
2623
|
-
ref target,
|
|
2624
|
-
ref message,
|
|
2625
|
-
priority,
|
|
2626
|
-
emissionId
|
|
2627
|
-
);
|
|
2628
2152
|
}
|
|
2153
|
+
|
|
2154
|
+
return writeIndex;
|
|
2629
2155
|
}
|
|
2630
2156
|
|
|
2631
|
-
|
|
2632
|
-
|
|
2157
|
+
private int FillFastWithContextFlatEntries<T>(
|
|
2158
|
+
Dictionary<int, IHandlerActionCache> byPriority,
|
|
2159
|
+
int priority,
|
|
2160
|
+
ContextFlatDispatchEntry<T>[] target,
|
|
2161
|
+
int writeIndex
|
|
2162
|
+
)
|
|
2163
|
+
where T : IMessage
|
|
2633
2164
|
{
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
TypedHandler<TMessage> typedHandler,
|
|
2639
|
-
long capturedGeneration
|
|
2165
|
+
if (
|
|
2166
|
+
byPriority == null
|
|
2167
|
+
|| !byPriority.TryGetValue(priority, out IHandlerActionCache erased)
|
|
2168
|
+
|| erased is not HandlerActionCache<FastHandlerWithContext<T>> cache
|
|
2640
2169
|
)
|
|
2641
2170
|
{
|
|
2642
|
-
|
|
2643
|
-
this.capturedGeneration = capturedGeneration;
|
|
2171
|
+
return writeIndex;
|
|
2644
2172
|
}
|
|
2645
2173
|
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
ref InstanceId target,
|
|
2650
|
-
ref TMessage message,
|
|
2651
|
-
int priority,
|
|
2652
|
-
long emissionId
|
|
2653
|
-
)
|
|
2174
|
+
List<FastHandlerWithContext<T>> ordered = cache.insertionOrder;
|
|
2175
|
+
int orderedCount = ordered.Count;
|
|
2176
|
+
for (int i = 0; i < orderedCount; ++i)
|
|
2654
2177
|
{
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2178
|
+
if (
|
|
2179
|
+
cache.entries.TryGetValue(
|
|
2180
|
+
ordered[i],
|
|
2181
|
+
out HandlerActionCache<FastHandlerWithContext<T>>.Entry entry
|
|
2182
|
+
)
|
|
2183
|
+
)
|
|
2659
2184
|
{
|
|
2660
|
-
|
|
2185
|
+
target[writeIndex++] = new ContextFlatDispatchEntry<T>(this, entry.handler);
|
|
2661
2186
|
}
|
|
2662
|
-
|
|
2663
|
-
typedHandler.HandleTargetedWithoutTargetingPostProcessing(
|
|
2664
|
-
ref target,
|
|
2665
|
-
ref message,
|
|
2666
|
-
priority,
|
|
2667
|
-
emissionId
|
|
2668
|
-
);
|
|
2669
2187
|
}
|
|
2188
|
+
|
|
2189
|
+
return writeIndex;
|
|
2670
2190
|
}
|
|
2671
2191
|
|
|
2672
|
-
|
|
2673
|
-
|
|
2192
|
+
private int FillDefaultWithContextFlatEntries<T>(
|
|
2193
|
+
Dictionary<int, IHandlerActionCache> byPriority,
|
|
2194
|
+
int priority,
|
|
2195
|
+
ContextFlatDispatchEntry<T>[] target,
|
|
2196
|
+
int writeIndex
|
|
2197
|
+
)
|
|
2198
|
+
where T : IMessage
|
|
2674
2199
|
{
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
TypedHandler<TMessage> typedHandler,
|
|
2680
|
-
long capturedGeneration
|
|
2200
|
+
if (
|
|
2201
|
+
byPriority == null
|
|
2202
|
+
|| !byPriority.TryGetValue(priority, out IHandlerActionCache erased)
|
|
2203
|
+
|| erased is not HandlerActionCache<Action<InstanceId, T>> cache
|
|
2681
2204
|
)
|
|
2682
2205
|
{
|
|
2683
|
-
|
|
2684
|
-
this.capturedGeneration = capturedGeneration;
|
|
2206
|
+
return writeIndex;
|
|
2685
2207
|
}
|
|
2686
2208
|
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
ref InstanceId source,
|
|
2691
|
-
ref TMessage message,
|
|
2692
|
-
int priority,
|
|
2693
|
-
long emissionId
|
|
2694
|
-
)
|
|
2209
|
+
List<Action<InstanceId, T>> ordered = cache.insertionOrder;
|
|
2210
|
+
int orderedCount = ordered.Count;
|
|
2211
|
+
for (int i = 0; i < orderedCount; ++i)
|
|
2695
2212
|
{
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2213
|
+
if (
|
|
2214
|
+
!cache.entries.TryGetValue(
|
|
2215
|
+
ordered[i],
|
|
2216
|
+
out HandlerActionCache<Action<InstanceId, T>>.Entry entry
|
|
2217
|
+
)
|
|
2218
|
+
)
|
|
2700
2219
|
{
|
|
2701
|
-
|
|
2220
|
+
continue;
|
|
2702
2221
|
}
|
|
2703
2222
|
|
|
2704
|
-
|
|
2223
|
+
// See FillDefaultFlatEntries: the adapter is created once at
|
|
2224
|
+
// registration time (AddTargetedWithoutTargetingHandler,
|
|
2225
|
+
// AddSourcedBroadcastWithoutSourceHandler, and their
|
|
2226
|
+
// post-processor siblings).
|
|
2227
|
+
if (entry.flatInvoker is FastHandlerWithContext<T> invoker)
|
|
2228
|
+
{
|
|
2229
|
+
target[writeIndex++] = new ContextFlatDispatchEntry<T>(this, invoker);
|
|
2230
|
+
}
|
|
2231
|
+
else
|
|
2232
|
+
{
|
|
2233
|
+
System.Diagnostics.Debug.Assert(
|
|
2234
|
+
false,
|
|
2235
|
+
"Default with-context registration is missing its "
|
|
2236
|
+
+ "FastHandlerWithContext flat invoker; every without-context "
|
|
2237
|
+
+ "Add* default path must adapt the augmented handler at "
|
|
2238
|
+
+ "registration time."
|
|
2239
|
+
);
|
|
2240
|
+
}
|
|
2705
2241
|
}
|
|
2242
|
+
|
|
2243
|
+
return writeIndex;
|
|
2706
2244
|
}
|
|
2707
2245
|
|
|
2708
|
-
internal sealed class
|
|
2709
|
-
where TMessage : IMessage
|
|
2246
|
+
internal sealed class HandlerActionCache<T> : DxMessaging.Core.Internal.IHandlerActionCache
|
|
2710
2247
|
{
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
long capturedGeneration
|
|
2717
|
-
)
|
|
2248
|
+
// Uses outer T as a field type -- reflection callers must close
|
|
2249
|
+
// via MakeGenericType(outer.GetGenericArguments()) before passing
|
|
2250
|
+
// this type to Activator.CreateInstance. See
|
|
2251
|
+
// Tests/Editor/Contract/ReflectionHelpers.cs::CloseNestedGeneric.
|
|
2252
|
+
internal readonly struct Entry
|
|
2718
2253
|
{
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2254
|
+
/// <summary>
|
|
2255
|
+
/// Initializes an entry used to track handler invocation counts.
|
|
2256
|
+
/// </summary>
|
|
2257
|
+
/// <param name="handler">Handler delegate being tracked.</param>
|
|
2258
|
+
/// <param name="count">Number of times the handler has been cached.</param>
|
|
2259
|
+
public Entry(T handler, int count)
|
|
2260
|
+
: this(handler, count, null) { }
|
|
2722
2261
|
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
{
|
|
2732
|
-
// Generation guard: 1 field read + 1 compare per dispatch on the hot path.
|
|
2733
|
-
// Sits at the top of Invoke so reclaimed wrappers return before handler-slot
|
|
2734
|
-
// walks when the outer wrapper has been reclaimed.
|
|
2735
|
-
if (typedHandler._outerGeneration != capturedGeneration)
|
|
2262
|
+
/// <summary>
|
|
2263
|
+
/// Initializes an entry that additionally carries a pre-resolved
|
|
2264
|
+
/// flat-dispatch invoker (see <see cref="flatInvoker"/>).
|
|
2265
|
+
/// </summary>
|
|
2266
|
+
/// <param name="handler">Handler delegate being tracked.</param>
|
|
2267
|
+
/// <param name="count">Number of times the handler has been cached.</param>
|
|
2268
|
+
/// <param name="flatInvoker">Pre-resolved flat-dispatch invoker, if any.</param>
|
|
2269
|
+
public Entry(T handler, int count, object flatInvoker)
|
|
2736
2270
|
{
|
|
2737
|
-
|
|
2271
|
+
this.handler = handler;
|
|
2272
|
+
this.count = count;
|
|
2273
|
+
this.flatInvoker = flatInvoker;
|
|
2738
2274
|
}
|
|
2739
2275
|
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2276
|
+
public readonly T handler;
|
|
2277
|
+
public readonly int count;
|
|
2278
|
+
|
|
2279
|
+
// Pre-resolved invoker consumed by the bus-side flat dispatch
|
|
2280
|
+
// snapshot (MessageBus.BuildMessageFlatDispatch). For
|
|
2281
|
+
// default Action<TMessage> registrations this holds a
|
|
2282
|
+
// FastHandler<TMessage> adapter wrapping the AUGMENTED
|
|
2283
|
+
// handler, created exactly ONCE at registration time so
|
|
2284
|
+
// snapshot rebuilds never allocate closures. For delegate
|
|
2285
|
+
// shapes the flat path does not consume (fast handlers, which
|
|
2286
|
+
// already ARE the invoker, and every targeted/broadcast
|
|
2287
|
+
// shape) this stays null. Refcount increments and decrements
|
|
2288
|
+
// preserve the first registration's invoker, mirroring the
|
|
2289
|
+
// first-augmented-handler-wins semantics of `handler`.
|
|
2290
|
+
public readonly object flatInvoker;
|
|
2746
2291
|
}
|
|
2747
|
-
}
|
|
2748
2292
|
|
|
2749
|
-
|
|
2750
|
-
where TMessage : IMessage
|
|
2751
|
-
{
|
|
2752
|
-
private readonly TypedHandler<TMessage> typedHandler;
|
|
2753
|
-
internal readonly long capturedGeneration;
|
|
2293
|
+
public readonly Dictionary<T, Entry> entries = new();
|
|
2754
2294
|
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2295
|
+
// Original-handler keys in first-registration order. Dictionary
|
|
2296
|
+
// enumeration order is NOT stable across Remove/Add churn (.NET
|
|
2297
|
+
// reuses freed slots LIFO), so dispatch snapshots are rebuilt from
|
|
2298
|
+
// this list instead of from <see cref="entries"/> to honor the
|
|
2299
|
+
// documented "same priority uses registration order" contract.
|
|
2300
|
+
// Invariants: contains exactly the keys of <see cref="entries"/>;
|
|
2301
|
+
// a key is appended on its FIRST registration only (refcount
|
|
2302
|
+
// increments do not move it) and removed when its refcount drops
|
|
2303
|
+
// to zero. Maintained exclusively by the AddHandler* family and
|
|
2304
|
+
// <see cref="DxMessaging.Core.Internal.IHandlerActionCache.Reset"/>.
|
|
2305
|
+
public readonly List<T> insertionOrder = new();
|
|
2306
|
+
public readonly List<T> cache = new();
|
|
2307
|
+
public long version;
|
|
2308
|
+
public long lastSeenVersion = -1;
|
|
2309
|
+
public long lastSeenEmissionId = -1;
|
|
2310
|
+
|
|
2311
|
+
/// <summary>Monotonic version field, read-only on the interface surface.</summary>
|
|
2312
|
+
long DxMessaging.Core.Internal.IHandlerActionCache.Version
|
|
2759
2313
|
{
|
|
2760
|
-
|
|
2761
|
-
|
|
2314
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2315
|
+
get => version;
|
|
2762
2316
|
}
|
|
2763
2317
|
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
MessageHandler messageHandler,
|
|
2767
|
-
ref InstanceId source,
|
|
2768
|
-
ref TMessage message,
|
|
2769
|
-
int priority,
|
|
2770
|
-
long emissionId
|
|
2771
|
-
)
|
|
2318
|
+
/// <summary>Most recent dispatcher-observed version; mutable through the staged dispatch path.</summary>
|
|
2319
|
+
long DxMessaging.Core.Internal.IHandlerActionCache.LastSeenVersion
|
|
2772
2320
|
{
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
{
|
|
2778
|
-
return;
|
|
2779
|
-
}
|
|
2780
|
-
|
|
2781
|
-
typedHandler.HandleSourcedBroadcastWithoutSource(
|
|
2782
|
-
ref source,
|
|
2783
|
-
ref message,
|
|
2784
|
-
priority,
|
|
2785
|
-
emissionId
|
|
2786
|
-
);
|
|
2321
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2322
|
+
get => lastSeenVersion;
|
|
2323
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2324
|
+
set => lastSeenVersion = value;
|
|
2787
2325
|
}
|
|
2788
|
-
}
|
|
2789
2326
|
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2327
|
+
/// <summary>Most recent dispatcher-observed bus emission id.</summary>
|
|
2328
|
+
long DxMessaging.Core.Internal.IHandlerActionCache.LastSeenEmissionId
|
|
2329
|
+
{
|
|
2330
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2331
|
+
get => lastSeenEmissionId;
|
|
2332
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2333
|
+
set => lastSeenEmissionId = value;
|
|
2334
|
+
}
|
|
2795
2335
|
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
long capturedGeneration
|
|
2799
|
-
)
|
|
2336
|
+
/// <summary>True iff the entries dictionary holds zero handlers.</summary>
|
|
2337
|
+
bool DxMessaging.Core.Internal.IHandlerActionCache.IsEmpty
|
|
2800
2338
|
{
|
|
2801
|
-
|
|
2802
|
-
|
|
2339
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
2340
|
+
get => entries.Count == 0;
|
|
2803
2341
|
}
|
|
2804
2342
|
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
int priority,
|
|
2811
|
-
long emissionId
|
|
2812
|
-
)
|
|
2343
|
+
/// <summary>
|
|
2344
|
+
/// Eviction-driven full clear; bumps <see cref="version"/> as the LAST step
|
|
2345
|
+
/// so captured dispatch closures observe invalidation.
|
|
2346
|
+
/// </summary>
|
|
2347
|
+
void DxMessaging.Core.Internal.IHandlerActionCache.Reset()
|
|
2813
2348
|
{
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2349
|
+
entries.Clear();
|
|
2350
|
+
insertionOrder.Clear();
|
|
2351
|
+
cache.Clear();
|
|
2352
|
+
lastSeenVersion = -1;
|
|
2353
|
+
lastSeenEmissionId = -1;
|
|
2354
|
+
unchecked
|
|
2818
2355
|
{
|
|
2819
|
-
|
|
2356
|
+
++version;
|
|
2820
2357
|
}
|
|
2821
|
-
|
|
2822
|
-
typedHandler.HandleBroadcastWithoutSourcePostProcessing(
|
|
2823
|
-
ref source,
|
|
2824
|
-
ref message,
|
|
2825
|
-
priority,
|
|
2826
|
-
emissionId
|
|
2827
|
-
);
|
|
2828
2358
|
}
|
|
2829
2359
|
}
|
|
2830
2360
|
|
|
@@ -2835,14 +2365,13 @@ namespace DxMessaging.Core
|
|
|
2835
2365
|
internal sealed class TypedHandler<T> : ITypedHandlerSlotSweeper
|
|
2836
2366
|
where T : IMessage
|
|
2837
2367
|
{
|
|
2838
|
-
// Typed storage: 20 typed slots + 6 global slots
|
|
2839
|
-
//
|
|
2840
|
-
//
|
|
2368
|
+
// Typed storage: 20 typed slots + 6 global slots. The legacy
|
|
2369
|
+
// named fields were deleted so new handler variants must pick an
|
|
2370
|
+
// explicit axis-indexed slot.
|
|
2841
2371
|
internal readonly TypedSlot<T>[] _slots = new TypedSlot<T>[TypedSlotIndex.Length];
|
|
2842
2372
|
internal readonly TypedGlobalSlot[] _globalSlots = new TypedGlobalSlot[
|
|
2843
2373
|
TypedGlobalSlotIndex.Length
|
|
2844
2374
|
];
|
|
2845
|
-
internal readonly object[] _dispatchLinks = new object[TypedDispatchLinkIndex.Length];
|
|
2846
2375
|
|
|
2847
2376
|
// Constructor exists solely so the [Conditional("DEBUG")]
|
|
2848
2377
|
// validator below runs at construction time. In Release builds
|
|
@@ -2855,7 +2384,6 @@ namespace DxMessaging.Core
|
|
|
2855
2384
|
ValidateSlotArrays();
|
|
2856
2385
|
}
|
|
2857
2386
|
|
|
2858
|
-
internal long _outerGeneration;
|
|
2859
2387
|
internal bool _markedForOuterRemoval;
|
|
2860
2388
|
|
|
2861
2389
|
int ITypedHandlerSlotSweeper.MessageTypeIndex
|
|
@@ -2885,12 +2413,6 @@ namespace DxMessaging.Core
|
|
|
2885
2413
|
$"_globalSlots length is {_globalSlots.Length} but TypedGlobalSlotIndex.Length is {TypedGlobalSlotIndex.Length}."
|
|
2886
2414
|
);
|
|
2887
2415
|
}
|
|
2888
|
-
if (_dispatchLinks.Length != TypedDispatchLinkIndex.Length)
|
|
2889
|
-
{
|
|
2890
|
-
throw new InvalidOperationException(
|
|
2891
|
-
$"_dispatchLinks length is {_dispatchLinks.Length} but TypedDispatchLinkIndex.Length is {TypedDispatchLinkIndex.Length}."
|
|
2892
|
-
);
|
|
2893
|
-
}
|
|
2894
2416
|
// Lazy registration writers update the slot arrays; this assertion still
|
|
2895
2417
|
// holds at construction (slots populate on first register,
|
|
2896
2418
|
// not on construction). The invariant flips meaning -- not
|
|
@@ -2913,15 +2435,6 @@ namespace DxMessaging.Core
|
|
|
2913
2435
|
);
|
|
2914
2436
|
}
|
|
2915
2437
|
}
|
|
2916
|
-
for (int i = 0; i < _dispatchLinks.Length; ++i)
|
|
2917
|
-
{
|
|
2918
|
-
if (_dispatchLinks[i] != null)
|
|
2919
|
-
{
|
|
2920
|
-
throw new InvalidOperationException(
|
|
2921
|
-
$"_dispatchLinks[{i}] is non-null at construction; expected null per TypedDispatchLinkIndex because links populate lazily on first dispatch-link request."
|
|
2922
|
-
);
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
2438
|
}
|
|
2926
2439
|
|
|
2927
2440
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
@@ -3079,11 +2592,6 @@ namespace DxMessaging.Core
|
|
|
3079
2592
|
}
|
|
3080
2593
|
}
|
|
3081
2594
|
|
|
3082
|
-
ClearDispatchLinks();
|
|
3083
|
-
unchecked
|
|
3084
|
-
{
|
|
3085
|
-
++_outerGeneration;
|
|
3086
|
-
}
|
|
3087
2595
|
return resetCount;
|
|
3088
2596
|
}
|
|
3089
2597
|
|
|
@@ -3119,12 +2627,7 @@ namespace DxMessaging.Core
|
|
|
3119
2627
|
return;
|
|
3120
2628
|
}
|
|
3121
2629
|
|
|
3122
|
-
ClearDispatchLinks();
|
|
3123
2630
|
_markedForOuterRemoval = true;
|
|
3124
|
-
unchecked
|
|
3125
|
-
{
|
|
3126
|
-
++_outerGeneration;
|
|
3127
|
-
}
|
|
3128
2631
|
}
|
|
3129
2632
|
|
|
3130
2633
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
@@ -3149,166 +2652,6 @@ namespace DxMessaging.Core
|
|
|
3149
2652
|
return false;
|
|
3150
2653
|
}
|
|
3151
2654
|
|
|
3152
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3153
|
-
private void ClearDispatchLinks()
|
|
3154
|
-
{
|
|
3155
|
-
for (int i = 0; i < _dispatchLinks.Length; ++i)
|
|
3156
|
-
{
|
|
3157
|
-
_dispatchLinks[i] = null;
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
|
|
3161
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3162
|
-
internal UntargetedDispatchLink<T> GetOrCreateUntargetedLink()
|
|
3163
|
-
{
|
|
3164
|
-
UntargetedDispatchLink<T> link =
|
|
3165
|
-
_dispatchLinks[TypedDispatchLinkIndex.UntargetedHandle]
|
|
3166
|
-
as UntargetedDispatchLink<T>;
|
|
3167
|
-
if (link == null)
|
|
3168
|
-
{
|
|
3169
|
-
link = new UntargetedDispatchLink<T>(this, _outerGeneration);
|
|
3170
|
-
_dispatchLinks[TypedDispatchLinkIndex.UntargetedHandle] = link;
|
|
3171
|
-
}
|
|
3172
|
-
|
|
3173
|
-
return link;
|
|
3174
|
-
}
|
|
3175
|
-
|
|
3176
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3177
|
-
internal UntargetedPostDispatchLink<T> GetOrCreateUntargetedPostLink()
|
|
3178
|
-
{
|
|
3179
|
-
UntargetedPostDispatchLink<T> link =
|
|
3180
|
-
_dispatchLinks[TypedDispatchLinkIndex.UntargetedPostProcess]
|
|
3181
|
-
as UntargetedPostDispatchLink<T>;
|
|
3182
|
-
if (link == null)
|
|
3183
|
-
{
|
|
3184
|
-
link = new UntargetedPostDispatchLink<T>(this, _outerGeneration);
|
|
3185
|
-
_dispatchLinks[TypedDispatchLinkIndex.UntargetedPostProcess] = link;
|
|
3186
|
-
}
|
|
3187
|
-
|
|
3188
|
-
return link;
|
|
3189
|
-
}
|
|
3190
|
-
|
|
3191
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3192
|
-
internal TargetedDispatchLink<T> GetOrCreateTargetedLink()
|
|
3193
|
-
{
|
|
3194
|
-
TargetedDispatchLink<T> link =
|
|
3195
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedHandle]
|
|
3196
|
-
as TargetedDispatchLink<T>;
|
|
3197
|
-
if (link == null)
|
|
3198
|
-
{
|
|
3199
|
-
link = new TargetedDispatchLink<T>(this, _outerGeneration);
|
|
3200
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedHandle] = link;
|
|
3201
|
-
}
|
|
3202
|
-
|
|
3203
|
-
return link;
|
|
3204
|
-
}
|
|
3205
|
-
|
|
3206
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3207
|
-
internal TargetedPostDispatchLink<T> GetOrCreateTargetedPostLink()
|
|
3208
|
-
{
|
|
3209
|
-
TargetedPostDispatchLink<T> link =
|
|
3210
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedPostProcess]
|
|
3211
|
-
as TargetedPostDispatchLink<T>;
|
|
3212
|
-
if (link == null)
|
|
3213
|
-
{
|
|
3214
|
-
link = new TargetedPostDispatchLink<T>(this, _outerGeneration);
|
|
3215
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedPostProcess] = link;
|
|
3216
|
-
}
|
|
3217
|
-
|
|
3218
|
-
return link;
|
|
3219
|
-
}
|
|
3220
|
-
|
|
3221
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3222
|
-
internal TargetedWithoutTargetingDispatchLink<T> GetOrCreateTargetedWithoutTargetingLink()
|
|
3223
|
-
{
|
|
3224
|
-
TargetedWithoutTargetingDispatchLink<T> link =
|
|
3225
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedHandleWithoutContext]
|
|
3226
|
-
as TargetedWithoutTargetingDispatchLink<T>;
|
|
3227
|
-
if (link == null)
|
|
3228
|
-
{
|
|
3229
|
-
link = new TargetedWithoutTargetingDispatchLink<T>(this, _outerGeneration);
|
|
3230
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedHandleWithoutContext] = link;
|
|
3231
|
-
}
|
|
3232
|
-
|
|
3233
|
-
return link;
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3237
|
-
internal TargetedWithoutTargetingPostDispatchLink<T> GetOrCreateTargetedWithoutTargetingPostLink()
|
|
3238
|
-
{
|
|
3239
|
-
TargetedWithoutTargetingPostDispatchLink<T> link =
|
|
3240
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedPostProcessWithoutContext]
|
|
3241
|
-
as TargetedWithoutTargetingPostDispatchLink<T>;
|
|
3242
|
-
if (link == null)
|
|
3243
|
-
{
|
|
3244
|
-
link = new TargetedWithoutTargetingPostDispatchLink<T>(this, _outerGeneration);
|
|
3245
|
-
_dispatchLinks[TypedDispatchLinkIndex.TargetedPostProcessWithoutContext] = link;
|
|
3246
|
-
}
|
|
3247
|
-
|
|
3248
|
-
return link;
|
|
3249
|
-
}
|
|
3250
|
-
|
|
3251
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3252
|
-
internal BroadcastDispatchLink<T> GetOrCreateBroadcastLink()
|
|
3253
|
-
{
|
|
3254
|
-
BroadcastDispatchLink<T> link =
|
|
3255
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastHandle]
|
|
3256
|
-
as BroadcastDispatchLink<T>;
|
|
3257
|
-
if (link == null)
|
|
3258
|
-
{
|
|
3259
|
-
link = new BroadcastDispatchLink<T>(this, _outerGeneration);
|
|
3260
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastHandle] = link;
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
|
-
return link;
|
|
3264
|
-
}
|
|
3265
|
-
|
|
3266
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3267
|
-
internal BroadcastPostDispatchLink<T> GetOrCreateBroadcastPostLink()
|
|
3268
|
-
{
|
|
3269
|
-
BroadcastPostDispatchLink<T> link =
|
|
3270
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastPostProcess]
|
|
3271
|
-
as BroadcastPostDispatchLink<T>;
|
|
3272
|
-
if (link == null)
|
|
3273
|
-
{
|
|
3274
|
-
link = new BroadcastPostDispatchLink<T>(this, _outerGeneration);
|
|
3275
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastPostProcess] = link;
|
|
3276
|
-
}
|
|
3277
|
-
|
|
3278
|
-
return link;
|
|
3279
|
-
}
|
|
3280
|
-
|
|
3281
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3282
|
-
internal BroadcastWithoutSourceDispatchLink<T> GetOrCreateBroadcastWithoutSourceLink()
|
|
3283
|
-
{
|
|
3284
|
-
BroadcastWithoutSourceDispatchLink<T> link =
|
|
3285
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastHandleWithoutContext]
|
|
3286
|
-
as BroadcastWithoutSourceDispatchLink<T>;
|
|
3287
|
-
if (link == null)
|
|
3288
|
-
{
|
|
3289
|
-
link = new BroadcastWithoutSourceDispatchLink<T>(this, _outerGeneration);
|
|
3290
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastHandleWithoutContext] = link;
|
|
3291
|
-
}
|
|
3292
|
-
|
|
3293
|
-
return link;
|
|
3294
|
-
}
|
|
3295
|
-
|
|
3296
|
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
3297
|
-
internal BroadcastWithoutSourcePostDispatchLink<T> GetOrCreateBroadcastWithoutSourcePostLink()
|
|
3298
|
-
{
|
|
3299
|
-
BroadcastWithoutSourcePostDispatchLink<T> link =
|
|
3300
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastPostProcessWithoutContext]
|
|
3301
|
-
as BroadcastWithoutSourcePostDispatchLink<T>;
|
|
3302
|
-
if (link == null)
|
|
3303
|
-
{
|
|
3304
|
-
link = new BroadcastWithoutSourcePostDispatchLink<T>(this, _outerGeneration);
|
|
3305
|
-
_dispatchLinks[TypedDispatchLinkIndex.BroadcastPostProcessWithoutContext] =
|
|
3306
|
-
link;
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
return link;
|
|
3310
|
-
}
|
|
3311
|
-
|
|
3312
2655
|
/// <summary>
|
|
3313
2656
|
/// Emits the UntargetedMessage to all subscribed listeners.
|
|
3314
2657
|
/// </summary>
|
|
@@ -3481,7 +2824,7 @@ namespace DxMessaging.Core
|
|
|
3481
2824
|
emissionId
|
|
3482
2825
|
);
|
|
3483
2826
|
int handlersCount = handlers.Count;
|
|
3484
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
2827
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
3485
2828
|
{
|
|
3486
2829
|
handlers[i](message);
|
|
3487
2830
|
}
|
|
@@ -3520,7 +2863,7 @@ namespace DxMessaging.Core
|
|
|
3520
2863
|
emissionId
|
|
3521
2864
|
);
|
|
3522
2865
|
int handlersCount = handlers.Count;
|
|
3523
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
2866
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
3524
2867
|
{
|
|
3525
2868
|
handlers[i](target, message);
|
|
3526
2869
|
}
|
|
@@ -3569,36 +2912,76 @@ namespace DxMessaging.Core
|
|
|
3569
2912
|
case 2:
|
|
3570
2913
|
{
|
|
3571
2914
|
handlers[0](source, message);
|
|
2915
|
+
if (handlers.Count < 2)
|
|
2916
|
+
{
|
|
2917
|
+
return;
|
|
2918
|
+
}
|
|
3572
2919
|
handlers[1](source, message);
|
|
3573
2920
|
return;
|
|
3574
2921
|
}
|
|
3575
2922
|
case 3:
|
|
3576
2923
|
{
|
|
3577
2924
|
handlers[0](source, message);
|
|
2925
|
+
if (handlers.Count < 2)
|
|
2926
|
+
{
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
3578
2929
|
handlers[1](source, message);
|
|
2930
|
+
if (handlers.Count < 3)
|
|
2931
|
+
{
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
3579
2934
|
handlers[2](source, message);
|
|
3580
2935
|
return;
|
|
3581
2936
|
}
|
|
3582
2937
|
case 4:
|
|
3583
2938
|
{
|
|
3584
2939
|
handlers[0](source, message);
|
|
2940
|
+
if (handlers.Count < 2)
|
|
2941
|
+
{
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
3585
2944
|
handlers[1](source, message);
|
|
2945
|
+
if (handlers.Count < 3)
|
|
2946
|
+
{
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
3586
2949
|
handlers[2](source, message);
|
|
2950
|
+
if (handlers.Count < 4)
|
|
2951
|
+
{
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
3587
2954
|
handlers[3](source, message);
|
|
3588
2955
|
return;
|
|
3589
2956
|
}
|
|
3590
2957
|
case 5:
|
|
3591
2958
|
{
|
|
3592
2959
|
handlers[0](source, message);
|
|
2960
|
+
if (handlers.Count < 2)
|
|
2961
|
+
{
|
|
2962
|
+
return;
|
|
2963
|
+
}
|
|
3593
2964
|
handlers[1](source, message);
|
|
2965
|
+
if (handlers.Count < 3)
|
|
2966
|
+
{
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
3594
2969
|
handlers[2](source, message);
|
|
2970
|
+
if (handlers.Count < 4)
|
|
2971
|
+
{
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
3595
2974
|
handlers[3](source, message);
|
|
2975
|
+
if (handlers.Count < 5)
|
|
2976
|
+
{
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
3596
2979
|
handlers[4](source, message);
|
|
3597
2980
|
return;
|
|
3598
2981
|
}
|
|
3599
2982
|
}
|
|
3600
2983
|
|
|
3601
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
2984
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
3602
2985
|
{
|
|
3603
2986
|
handlers[i](source, message);
|
|
3604
2987
|
}
|
|
@@ -3763,6 +3146,10 @@ namespace DxMessaging.Core
|
|
|
3763
3146
|
IMessageBus messageBus
|
|
3764
3147
|
)
|
|
3765
3148
|
{
|
|
3149
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3150
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3151
|
+
// resolve default registrations without allocating closures.
|
|
3152
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
3766
3153
|
return AddHandlerPreservingPriorityKey(
|
|
3767
3154
|
target,
|
|
3768
3155
|
GetOrCreateContextHandlers(TypedSlotIndex.TargetedHandleDefault),
|
|
@@ -3770,7 +3157,8 @@ namespace DxMessaging.Core
|
|
|
3770
3157
|
handler,
|
|
3771
3158
|
deregistration,
|
|
3772
3159
|
priority,
|
|
3773
|
-
messageBus
|
|
3160
|
+
messageBus,
|
|
3161
|
+
flatInvoker
|
|
3774
3162
|
);
|
|
3775
3163
|
}
|
|
3776
3164
|
|
|
@@ -3817,6 +3205,12 @@ namespace DxMessaging.Core
|
|
|
3817
3205
|
IMessageBus messageBus
|
|
3818
3206
|
)
|
|
3819
3207
|
{
|
|
3208
|
+
// Adapt the AUGMENTED handler to FastHandlerWithContext form
|
|
3209
|
+
// exactly once, at registration time, so bus-side flat snapshot
|
|
3210
|
+
// rebuilds resolve default registrations without allocating
|
|
3211
|
+
// closures.
|
|
3212
|
+
FastHandlerWithContext<T> flatInvoker = (ref InstanceId context, ref T message) =>
|
|
3213
|
+
handler(context, message);
|
|
3820
3214
|
return AddHandlerPreservingPriorityKey(
|
|
3821
3215
|
GetOrCreatePriorityHandlers(
|
|
3822
3216
|
TypedSlotIndex.TargetedHandleWithoutContext,
|
|
@@ -3826,7 +3220,8 @@ namespace DxMessaging.Core
|
|
|
3826
3220
|
handler,
|
|
3827
3221
|
deregistration,
|
|
3828
3222
|
priority,
|
|
3829
|
-
messageBus
|
|
3223
|
+
messageBus,
|
|
3224
|
+
flatInvoker
|
|
3830
3225
|
);
|
|
3831
3226
|
}
|
|
3832
3227
|
|
|
@@ -3873,6 +3268,10 @@ namespace DxMessaging.Core
|
|
|
3873
3268
|
IMessageBus messageBus
|
|
3874
3269
|
)
|
|
3875
3270
|
{
|
|
3271
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3272
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3273
|
+
// resolve default registrations without allocating closures.
|
|
3274
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
3876
3275
|
return AddHandlerPreservingPriorityKey(
|
|
3877
3276
|
GetOrCreatePriorityHandlers(
|
|
3878
3277
|
TypedSlotIndex.UntargetedHandleDefault,
|
|
@@ -3882,7 +3281,8 @@ namespace DxMessaging.Core
|
|
|
3882
3281
|
handler,
|
|
3883
3282
|
deregistration,
|
|
3884
3283
|
priority,
|
|
3885
|
-
messageBus
|
|
3284
|
+
messageBus,
|
|
3285
|
+
flatInvoker
|
|
3886
3286
|
);
|
|
3887
3287
|
}
|
|
3888
3288
|
|
|
@@ -3931,6 +3331,10 @@ namespace DxMessaging.Core
|
|
|
3931
3331
|
IMessageBus messageBus
|
|
3932
3332
|
)
|
|
3933
3333
|
{
|
|
3334
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3335
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3336
|
+
// resolve default registrations without allocating closures.
|
|
3337
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
3934
3338
|
return AddHandlerPreservingPriorityKey(
|
|
3935
3339
|
source,
|
|
3936
3340
|
GetOrCreateContextHandlers(TypedSlotIndex.BroadcastHandleDefault),
|
|
@@ -3938,7 +3342,8 @@ namespace DxMessaging.Core
|
|
|
3938
3342
|
handler,
|
|
3939
3343
|
deregistration,
|
|
3940
3344
|
priority,
|
|
3941
|
-
messageBus
|
|
3345
|
+
messageBus,
|
|
3346
|
+
flatInvoker
|
|
3942
3347
|
);
|
|
3943
3348
|
}
|
|
3944
3349
|
|
|
@@ -3985,6 +3390,12 @@ namespace DxMessaging.Core
|
|
|
3985
3390
|
IMessageBus messageBus
|
|
3986
3391
|
)
|
|
3987
3392
|
{
|
|
3393
|
+
// Adapt the AUGMENTED handler to FastHandlerWithContext form
|
|
3394
|
+
// exactly once, at registration time, so bus-side flat snapshot
|
|
3395
|
+
// rebuilds resolve default registrations without allocating
|
|
3396
|
+
// closures.
|
|
3397
|
+
FastHandlerWithContext<T> flatInvoker = (ref InstanceId context, ref T message) =>
|
|
3398
|
+
handler(context, message);
|
|
3988
3399
|
// Preserve the priority bucket during the current emission so frozen snapshots remain valid
|
|
3989
3400
|
return AddHandlerPreservingPriorityKey(
|
|
3990
3401
|
GetOrCreatePriorityHandlers(
|
|
@@ -3995,7 +3406,8 @@ namespace DxMessaging.Core
|
|
|
3995
3406
|
handler,
|
|
3996
3407
|
deregistration,
|
|
3997
3408
|
priority,
|
|
3998
|
-
messageBus
|
|
3409
|
+
messageBus,
|
|
3410
|
+
flatInvoker
|
|
3999
3411
|
);
|
|
4000
3412
|
}
|
|
4001
3413
|
|
|
@@ -4175,6 +3587,10 @@ namespace DxMessaging.Core
|
|
|
4175
3587
|
IMessageBus messageBus
|
|
4176
3588
|
)
|
|
4177
3589
|
{
|
|
3590
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3591
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3592
|
+
// resolve default registrations without allocating closures.
|
|
3593
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
4178
3594
|
return AddHandlerPreservingPriorityKey(
|
|
4179
3595
|
GetOrCreatePriorityHandlers(
|
|
4180
3596
|
TypedSlotIndex.UntargetedPostProcessDefault,
|
|
@@ -4184,7 +3600,8 @@ namespace DxMessaging.Core
|
|
|
4184
3600
|
handler,
|
|
4185
3601
|
deregistration,
|
|
4186
3602
|
priority,
|
|
4187
|
-
messageBus
|
|
3603
|
+
messageBus,
|
|
3604
|
+
flatInvoker
|
|
4188
3605
|
);
|
|
4189
3606
|
}
|
|
4190
3607
|
|
|
@@ -4233,6 +3650,10 @@ namespace DxMessaging.Core
|
|
|
4233
3650
|
IMessageBus messageBus
|
|
4234
3651
|
)
|
|
4235
3652
|
{
|
|
3653
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3654
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3655
|
+
// resolve default registrations without allocating closures.
|
|
3656
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
4236
3657
|
return AddHandlerPreservingPriorityKey(
|
|
4237
3658
|
target,
|
|
4238
3659
|
GetOrCreateContextHandlers(TypedSlotIndex.TargetedPostProcessDefault),
|
|
@@ -4240,7 +3661,8 @@ namespace DxMessaging.Core
|
|
|
4240
3661
|
handler,
|
|
4241
3662
|
deregistration,
|
|
4242
3663
|
priority,
|
|
4243
|
-
messageBus
|
|
3664
|
+
messageBus,
|
|
3665
|
+
flatInvoker
|
|
4244
3666
|
);
|
|
4245
3667
|
}
|
|
4246
3668
|
|
|
@@ -4287,6 +3709,12 @@ namespace DxMessaging.Core
|
|
|
4287
3709
|
IMessageBus messageBus
|
|
4288
3710
|
)
|
|
4289
3711
|
{
|
|
3712
|
+
// Adapt the AUGMENTED handler to FastHandlerWithContext form
|
|
3713
|
+
// exactly once, at registration time, so bus-side flat snapshot
|
|
3714
|
+
// rebuilds resolve default registrations without allocating
|
|
3715
|
+
// closures.
|
|
3716
|
+
FastHandlerWithContext<T> flatInvoker = (ref InstanceId context, ref T message) =>
|
|
3717
|
+
handler(context, message);
|
|
4290
3718
|
return AddHandlerPreservingPriorityKey(
|
|
4291
3719
|
GetOrCreatePriorityHandlers(
|
|
4292
3720
|
TypedSlotIndex.TargetedPostProcessWithoutContext,
|
|
@@ -4296,7 +3724,8 @@ namespace DxMessaging.Core
|
|
|
4296
3724
|
handler,
|
|
4297
3725
|
deregistration,
|
|
4298
3726
|
priority,
|
|
4299
|
-
messageBus
|
|
3727
|
+
messageBus,
|
|
3728
|
+
flatInvoker
|
|
4300
3729
|
);
|
|
4301
3730
|
}
|
|
4302
3731
|
|
|
@@ -4345,6 +3774,10 @@ namespace DxMessaging.Core
|
|
|
4345
3774
|
IMessageBus messageBus
|
|
4346
3775
|
)
|
|
4347
3776
|
{
|
|
3777
|
+
// Adapt the AUGMENTED handler to FastHandler form exactly once,
|
|
3778
|
+
// at registration time, so bus-side flat snapshot rebuilds
|
|
3779
|
+
// resolve default registrations without allocating closures.
|
|
3780
|
+
FastHandler<T> flatInvoker = (ref T message) => handler(message);
|
|
4348
3781
|
return AddHandlerPreservingPriorityKey(
|
|
4349
3782
|
source,
|
|
4350
3783
|
GetOrCreateContextHandlers(TypedSlotIndex.BroadcastPostProcessDefault),
|
|
@@ -4352,7 +3785,8 @@ namespace DxMessaging.Core
|
|
|
4352
3785
|
handler,
|
|
4353
3786
|
deregistration,
|
|
4354
3787
|
priority,
|
|
4355
|
-
messageBus
|
|
3788
|
+
messageBus,
|
|
3789
|
+
flatInvoker
|
|
4356
3790
|
);
|
|
4357
3791
|
}
|
|
4358
3792
|
|
|
@@ -4399,6 +3833,12 @@ namespace DxMessaging.Core
|
|
|
4399
3833
|
IMessageBus messageBus
|
|
4400
3834
|
)
|
|
4401
3835
|
{
|
|
3836
|
+
// Adapt the AUGMENTED handler to FastHandlerWithContext form
|
|
3837
|
+
// exactly once, at registration time, so bus-side flat snapshot
|
|
3838
|
+
// rebuilds resolve default registrations without allocating
|
|
3839
|
+
// closures.
|
|
3840
|
+
FastHandlerWithContext<T> flatInvoker = (ref InstanceId context, ref T message) =>
|
|
3841
|
+
handler(context, message);
|
|
4402
3842
|
return AddHandlerPreservingPriorityKey(
|
|
4403
3843
|
GetOrCreatePriorityHandlers(
|
|
4404
3844
|
TypedSlotIndex.BroadcastPostProcessWithoutContext,
|
|
@@ -4408,7 +3848,8 @@ namespace DxMessaging.Core
|
|
|
4408
3848
|
handler,
|
|
4409
3849
|
deregistration,
|
|
4410
3850
|
priority,
|
|
4411
|
-
messageBus
|
|
3851
|
+
messageBus,
|
|
3852
|
+
flatInvoker
|
|
4412
3853
|
);
|
|
4413
3854
|
}
|
|
4414
3855
|
|
|
@@ -4455,6 +3896,10 @@ namespace DxMessaging.Core
|
|
|
4455
3896
|
// MessageHandlers or routing through AddSourcedBroadcastWithoutSourceHandler /
|
|
4456
3897
|
// AddTargetedWithoutTargetingHandler to avoid the per-(context,priority)
|
|
4457
3898
|
// outer-dictionary growth.
|
|
3899
|
+
// `flatInvoker` carries the pre-resolved flat-dispatch invoker for
|
|
3900
|
+
// default-shape registrations the bus-side flat snapshot consumes
|
|
3901
|
+
// (FastHandler adapter wrapping the augmented handler); see
|
|
3902
|
+
// HandlerActionCache.Entry.flatInvoker.
|
|
4458
3903
|
private Action AddHandlerPreservingPriorityKey<TU>(
|
|
4459
3904
|
InstanceId context,
|
|
4460
3905
|
Dictionary<InstanceId, Dictionary<int, IHandlerActionCache>> handlersByContext,
|
|
@@ -4462,7 +3907,8 @@ namespace DxMessaging.Core
|
|
|
4462
3907
|
TU augmentedHandler,
|
|
4463
3908
|
Action deregistration,
|
|
4464
3909
|
int priority,
|
|
4465
|
-
IMessageBus messageBus
|
|
3910
|
+
IMessageBus messageBus,
|
|
3911
|
+
object flatInvoker = null
|
|
4466
3912
|
)
|
|
4467
3913
|
{
|
|
4468
3914
|
if (
|
|
@@ -4497,10 +3943,18 @@ namespace DxMessaging.Core
|
|
|
4497
3943
|
|
|
4498
3944
|
bool firstRegistration = entry.count == 0;
|
|
4499
3945
|
entry = firstRegistration
|
|
4500
|
-
? new HandlerActionCache<TU>.Entry(augmentedHandler, 1)
|
|
4501
|
-
: new HandlerActionCache<TU>.Entry(
|
|
3946
|
+
? new HandlerActionCache<TU>.Entry(augmentedHandler, 1, flatInvoker)
|
|
3947
|
+
: new HandlerActionCache<TU>.Entry(
|
|
3948
|
+
entry.handler,
|
|
3949
|
+
entry.count + 1,
|
|
3950
|
+
entry.flatInvoker
|
|
3951
|
+
);
|
|
4502
3952
|
|
|
4503
3953
|
cache.entries[originalHandler] = entry;
|
|
3954
|
+
if (firstRegistration)
|
|
3955
|
+
{
|
|
3956
|
+
cache.insertionOrder.Add(originalHandler);
|
|
3957
|
+
}
|
|
4504
3958
|
cache.version++;
|
|
4505
3959
|
TypedSlot<T> slot = FindContextSlot(handlersByContext);
|
|
4506
3960
|
if (slot != null)
|
|
@@ -4580,6 +4034,15 @@ namespace DxMessaging.Core
|
|
|
4580
4034
|
if (localEntry.count <= 1)
|
|
4581
4035
|
{
|
|
4582
4036
|
_ = localCache.entries.Remove(originalHandler);
|
|
4037
|
+
// List.Remove is O(n) over the same-priority bucket.
|
|
4038
|
+
// Accepted tradeoff (here and at every sibling
|
|
4039
|
+
// deregistration site): buckets are small in practice,
|
|
4040
|
+
// removal is a cold churn path, and the list keeps
|
|
4041
|
+
// steady-state dispatch allocation-free while
|
|
4042
|
+
// preserving first-registration order, unlike
|
|
4043
|
+
// Dictionary enumeration whose freed slots are reused
|
|
4044
|
+
// LIFO.
|
|
4045
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
4583
4046
|
localCache.version++;
|
|
4584
4047
|
if (localSlot != null)
|
|
4585
4048
|
{
|
|
@@ -4592,7 +4055,8 @@ namespace DxMessaging.Core
|
|
|
4592
4055
|
|
|
4593
4056
|
localEntry = new HandlerActionCache<TU>.Entry(
|
|
4594
4057
|
localEntry.handler,
|
|
4595
|
-
localEntry.count - 1
|
|
4058
|
+
localEntry.count - 1,
|
|
4059
|
+
localEntry.flatInvoker
|
|
4596
4060
|
);
|
|
4597
4061
|
|
|
4598
4062
|
localCache.entries[originalHandler] = localEntry;
|
|
@@ -4648,6 +4112,10 @@ namespace DxMessaging.Core
|
|
|
4648
4112
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
4649
4113
|
|
|
4650
4114
|
cache.entries[originalHandler] = entry;
|
|
4115
|
+
if (firstRegistration)
|
|
4116
|
+
{
|
|
4117
|
+
cache.insertionOrder.Add(originalHandler);
|
|
4118
|
+
}
|
|
4651
4119
|
cache.version++;
|
|
4652
4120
|
|
|
4653
4121
|
Dictionary<
|
|
@@ -4686,6 +4154,7 @@ namespace DxMessaging.Core
|
|
|
4686
4154
|
if (localEntry.count <= 1)
|
|
4687
4155
|
{
|
|
4688
4156
|
_ = localCache.entries.Remove(originalHandler);
|
|
4157
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
4689
4158
|
localCache.version++;
|
|
4690
4159
|
// Deliberately keep the priority and context mappings to preserve
|
|
4691
4160
|
// frozen snapshots for the current emission.
|
|
@@ -4809,7 +4278,7 @@ namespace DxMessaging.Core
|
|
|
4809
4278
|
return;
|
|
4810
4279
|
}
|
|
4811
4280
|
|
|
4812
|
-
ref T typedMessage = ref
|
|
4281
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
4813
4282
|
List<FastHandler<T>> handlers = GetOrAddNewHandlerStack(cache, emissionId);
|
|
4814
4283
|
int handlersCount = handlers.Count;
|
|
4815
4284
|
switch (handlersCount)
|
|
@@ -4822,36 +4291,76 @@ namespace DxMessaging.Core
|
|
|
4822
4291
|
case 2:
|
|
4823
4292
|
{
|
|
4824
4293
|
handlers[0](ref typedMessage);
|
|
4294
|
+
if (handlers.Count < 2)
|
|
4295
|
+
{
|
|
4296
|
+
return;
|
|
4297
|
+
}
|
|
4825
4298
|
handlers[1](ref typedMessage);
|
|
4826
4299
|
return;
|
|
4827
4300
|
}
|
|
4828
4301
|
case 3:
|
|
4829
4302
|
{
|
|
4830
4303
|
handlers[0](ref typedMessage);
|
|
4304
|
+
if (handlers.Count < 2)
|
|
4305
|
+
{
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4831
4308
|
handlers[1](ref typedMessage);
|
|
4309
|
+
if (handlers.Count < 3)
|
|
4310
|
+
{
|
|
4311
|
+
return;
|
|
4312
|
+
}
|
|
4832
4313
|
handlers[2](ref typedMessage);
|
|
4833
4314
|
return;
|
|
4834
4315
|
}
|
|
4835
4316
|
case 4:
|
|
4836
4317
|
{
|
|
4837
4318
|
handlers[0](ref typedMessage);
|
|
4319
|
+
if (handlers.Count < 2)
|
|
4320
|
+
{
|
|
4321
|
+
return;
|
|
4322
|
+
}
|
|
4838
4323
|
handlers[1](ref typedMessage);
|
|
4324
|
+
if (handlers.Count < 3)
|
|
4325
|
+
{
|
|
4326
|
+
return;
|
|
4327
|
+
}
|
|
4839
4328
|
handlers[2](ref typedMessage);
|
|
4329
|
+
if (handlers.Count < 4)
|
|
4330
|
+
{
|
|
4331
|
+
return;
|
|
4332
|
+
}
|
|
4840
4333
|
handlers[3](ref typedMessage);
|
|
4841
4334
|
return;
|
|
4842
4335
|
}
|
|
4843
4336
|
case 5:
|
|
4844
4337
|
{
|
|
4845
4338
|
handlers[0](ref typedMessage);
|
|
4339
|
+
if (handlers.Count < 2)
|
|
4340
|
+
{
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4846
4343
|
handlers[1](ref typedMessage);
|
|
4344
|
+
if (handlers.Count < 3)
|
|
4345
|
+
{
|
|
4346
|
+
return;
|
|
4347
|
+
}
|
|
4847
4348
|
handlers[2](ref typedMessage);
|
|
4349
|
+
if (handlers.Count < 4)
|
|
4350
|
+
{
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4848
4353
|
handlers[3](ref typedMessage);
|
|
4354
|
+
if (handlers.Count < 5)
|
|
4355
|
+
{
|
|
4356
|
+
return;
|
|
4357
|
+
}
|
|
4849
4358
|
handlers[4](ref typedMessage);
|
|
4850
4359
|
return;
|
|
4851
4360
|
}
|
|
4852
4361
|
}
|
|
4853
4362
|
|
|
4854
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
4363
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
4855
4364
|
{
|
|
4856
4365
|
handlers[i](ref typedMessage);
|
|
4857
4366
|
}
|
|
@@ -4880,7 +4389,7 @@ namespace DxMessaging.Core
|
|
|
4880
4389
|
return;
|
|
4881
4390
|
}
|
|
4882
4391
|
|
|
4883
|
-
ref T typedMessage = ref
|
|
4392
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
4884
4393
|
List<FastHandler<T>> handlers = GetOrAddNewHandlerStack(cache, emissionId);
|
|
4885
4394
|
int handlersCount = handlers.Count;
|
|
4886
4395
|
switch (handlersCount)
|
|
@@ -4893,36 +4402,76 @@ namespace DxMessaging.Core
|
|
|
4893
4402
|
case 2:
|
|
4894
4403
|
{
|
|
4895
4404
|
handlers[0](ref typedMessage);
|
|
4405
|
+
if (handlers.Count < 2)
|
|
4406
|
+
{
|
|
4407
|
+
return;
|
|
4408
|
+
}
|
|
4896
4409
|
handlers[1](ref typedMessage);
|
|
4897
4410
|
return;
|
|
4898
4411
|
}
|
|
4899
4412
|
case 3:
|
|
4900
4413
|
{
|
|
4901
4414
|
handlers[0](ref typedMessage);
|
|
4415
|
+
if (handlers.Count < 2)
|
|
4416
|
+
{
|
|
4417
|
+
return;
|
|
4418
|
+
}
|
|
4902
4419
|
handlers[1](ref typedMessage);
|
|
4420
|
+
if (handlers.Count < 3)
|
|
4421
|
+
{
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4903
4424
|
handlers[2](ref typedMessage);
|
|
4904
4425
|
return;
|
|
4905
4426
|
}
|
|
4906
4427
|
case 4:
|
|
4907
4428
|
{
|
|
4908
4429
|
handlers[0](ref typedMessage);
|
|
4430
|
+
if (handlers.Count < 2)
|
|
4431
|
+
{
|
|
4432
|
+
return;
|
|
4433
|
+
}
|
|
4909
4434
|
handlers[1](ref typedMessage);
|
|
4435
|
+
if (handlers.Count < 3)
|
|
4436
|
+
{
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4910
4439
|
handlers[2](ref typedMessage);
|
|
4440
|
+
if (handlers.Count < 4)
|
|
4441
|
+
{
|
|
4442
|
+
return;
|
|
4443
|
+
}
|
|
4911
4444
|
handlers[3](ref typedMessage);
|
|
4912
4445
|
return;
|
|
4913
4446
|
}
|
|
4914
4447
|
case 5:
|
|
4915
4448
|
{
|
|
4916
4449
|
handlers[0](ref typedMessage);
|
|
4450
|
+
if (handlers.Count < 2)
|
|
4451
|
+
{
|
|
4452
|
+
return;
|
|
4453
|
+
}
|
|
4917
4454
|
handlers[1](ref typedMessage);
|
|
4455
|
+
if (handlers.Count < 3)
|
|
4456
|
+
{
|
|
4457
|
+
return;
|
|
4458
|
+
}
|
|
4918
4459
|
handlers[2](ref typedMessage);
|
|
4460
|
+
if (handlers.Count < 4)
|
|
4461
|
+
{
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4919
4464
|
handlers[3](ref typedMessage);
|
|
4465
|
+
if (handlers.Count < 5)
|
|
4466
|
+
{
|
|
4467
|
+
return;
|
|
4468
|
+
}
|
|
4920
4469
|
handlers[4](ref typedMessage);
|
|
4921
4470
|
return;
|
|
4922
4471
|
}
|
|
4923
4472
|
}
|
|
4924
4473
|
|
|
4925
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
4474
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
4926
4475
|
{
|
|
4927
4476
|
handlers[i](ref typedMessage);
|
|
4928
4477
|
}
|
|
@@ -4956,7 +4505,7 @@ namespace DxMessaging.Core
|
|
|
4956
4505
|
return;
|
|
4957
4506
|
}
|
|
4958
4507
|
|
|
4959
|
-
ref TU typedMessage = ref
|
|
4508
|
+
ref TU typedMessage = ref DxUnsafe.As<TMessage, TU>(ref message);
|
|
4960
4509
|
List<FastHandler<TU>> handlers = GetOrAddNewHandlerStack(cache, emissionId);
|
|
4961
4510
|
int handlersCount = handlers.Count;
|
|
4962
4511
|
if (handlersCount == 0)
|
|
@@ -4973,36 +4522,76 @@ namespace DxMessaging.Core
|
|
|
4973
4522
|
case 2:
|
|
4974
4523
|
{
|
|
4975
4524
|
handlers[0](ref typedMessage);
|
|
4525
|
+
if (handlers.Count < 2)
|
|
4526
|
+
{
|
|
4527
|
+
return;
|
|
4528
|
+
}
|
|
4976
4529
|
handlers[1](ref typedMessage);
|
|
4977
4530
|
return;
|
|
4978
4531
|
}
|
|
4979
4532
|
case 3:
|
|
4980
4533
|
{
|
|
4981
4534
|
handlers[0](ref typedMessage);
|
|
4535
|
+
if (handlers.Count < 2)
|
|
4536
|
+
{
|
|
4537
|
+
return;
|
|
4538
|
+
}
|
|
4982
4539
|
handlers[1](ref typedMessage);
|
|
4540
|
+
if (handlers.Count < 3)
|
|
4541
|
+
{
|
|
4542
|
+
return;
|
|
4543
|
+
}
|
|
4983
4544
|
handlers[2](ref typedMessage);
|
|
4984
4545
|
return;
|
|
4985
4546
|
}
|
|
4986
4547
|
case 4:
|
|
4987
4548
|
{
|
|
4988
4549
|
handlers[0](ref typedMessage);
|
|
4550
|
+
if (handlers.Count < 2)
|
|
4551
|
+
{
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4989
4554
|
handlers[1](ref typedMessage);
|
|
4555
|
+
if (handlers.Count < 3)
|
|
4556
|
+
{
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4990
4559
|
handlers[2](ref typedMessage);
|
|
4560
|
+
if (handlers.Count < 4)
|
|
4561
|
+
{
|
|
4562
|
+
return;
|
|
4563
|
+
}
|
|
4991
4564
|
handlers[3](ref typedMessage);
|
|
4992
4565
|
return;
|
|
4993
4566
|
}
|
|
4994
4567
|
case 5:
|
|
4995
4568
|
{
|
|
4996
4569
|
handlers[0](ref typedMessage);
|
|
4570
|
+
if (handlers.Count < 2)
|
|
4571
|
+
{
|
|
4572
|
+
return;
|
|
4573
|
+
}
|
|
4997
4574
|
handlers[1](ref typedMessage);
|
|
4575
|
+
if (handlers.Count < 3)
|
|
4576
|
+
{
|
|
4577
|
+
return;
|
|
4578
|
+
}
|
|
4998
4579
|
handlers[2](ref typedMessage);
|
|
4580
|
+
if (handlers.Count < 4)
|
|
4581
|
+
{
|
|
4582
|
+
return;
|
|
4583
|
+
}
|
|
4999
4584
|
handlers[3](ref typedMessage);
|
|
4585
|
+
if (handlers.Count < 5)
|
|
4586
|
+
{
|
|
4587
|
+
return;
|
|
4588
|
+
}
|
|
5000
4589
|
handlers[4](ref typedMessage);
|
|
5001
4590
|
return;
|
|
5002
4591
|
}
|
|
5003
4592
|
}
|
|
5004
4593
|
|
|
5005
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
4594
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
5006
4595
|
{
|
|
5007
4596
|
handlers[i](ref typedMessage);
|
|
5008
4597
|
}
|
|
@@ -5025,7 +4614,7 @@ namespace DxMessaging.Core
|
|
|
5025
4614
|
return;
|
|
5026
4615
|
}
|
|
5027
4616
|
|
|
5028
|
-
ref TU typedMessage = ref
|
|
4617
|
+
ref TU typedMessage = ref DxUnsafe.As<TMessage, TU>(ref message);
|
|
5029
4618
|
List<FastHandlerWithContext<TU>> handlers = GetOrAddNewHandlerStack(
|
|
5030
4619
|
cache,
|
|
5031
4620
|
emissionId
|
|
@@ -5045,36 +4634,76 @@ namespace DxMessaging.Core
|
|
|
5045
4634
|
case 2:
|
|
5046
4635
|
{
|
|
5047
4636
|
handlers[0](ref context, ref typedMessage);
|
|
4637
|
+
if (handlers.Count < 2)
|
|
4638
|
+
{
|
|
4639
|
+
return;
|
|
4640
|
+
}
|
|
5048
4641
|
handlers[1](ref context, ref typedMessage);
|
|
5049
4642
|
return;
|
|
5050
4643
|
}
|
|
5051
4644
|
case 3:
|
|
5052
4645
|
{
|
|
5053
4646
|
handlers[0](ref context, ref typedMessage);
|
|
4647
|
+
if (handlers.Count < 2)
|
|
4648
|
+
{
|
|
4649
|
+
return;
|
|
4650
|
+
}
|
|
5054
4651
|
handlers[1](ref context, ref typedMessage);
|
|
4652
|
+
if (handlers.Count < 3)
|
|
4653
|
+
{
|
|
4654
|
+
return;
|
|
4655
|
+
}
|
|
5055
4656
|
handlers[2](ref context, ref typedMessage);
|
|
5056
4657
|
return;
|
|
5057
4658
|
}
|
|
5058
4659
|
case 4:
|
|
5059
4660
|
{
|
|
5060
4661
|
handlers[0](ref context, ref typedMessage);
|
|
4662
|
+
if (handlers.Count < 2)
|
|
4663
|
+
{
|
|
4664
|
+
return;
|
|
4665
|
+
}
|
|
5061
4666
|
handlers[1](ref context, ref typedMessage);
|
|
4667
|
+
if (handlers.Count < 3)
|
|
4668
|
+
{
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
5062
4671
|
handlers[2](ref context, ref typedMessage);
|
|
4672
|
+
if (handlers.Count < 4)
|
|
4673
|
+
{
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
5063
4676
|
handlers[3](ref context, ref typedMessage);
|
|
5064
4677
|
return;
|
|
5065
4678
|
}
|
|
5066
4679
|
case 5:
|
|
5067
4680
|
{
|
|
5068
4681
|
handlers[0](ref context, ref typedMessage);
|
|
4682
|
+
if (handlers.Count < 2)
|
|
4683
|
+
{
|
|
4684
|
+
return;
|
|
4685
|
+
}
|
|
5069
4686
|
handlers[1](ref context, ref typedMessage);
|
|
4687
|
+
if (handlers.Count < 3)
|
|
4688
|
+
{
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
5070
4691
|
handlers[2](ref context, ref typedMessage);
|
|
4692
|
+
if (handlers.Count < 4)
|
|
4693
|
+
{
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
5071
4696
|
handlers[3](ref context, ref typedMessage);
|
|
4697
|
+
if (handlers.Count < 5)
|
|
4698
|
+
{
|
|
4699
|
+
return;
|
|
4700
|
+
}
|
|
5072
4701
|
handlers[4](ref context, ref typedMessage);
|
|
5073
4702
|
return;
|
|
5074
4703
|
}
|
|
5075
4704
|
}
|
|
5076
4705
|
|
|
5077
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
4706
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
5078
4707
|
{
|
|
5079
4708
|
handlers[i](ref context, ref typedMessage);
|
|
5080
4709
|
}
|
|
@@ -5156,7 +4785,7 @@ namespace DxMessaging.Core
|
|
|
5156
4785
|
return;
|
|
5157
4786
|
}
|
|
5158
4787
|
|
|
5159
|
-
ref TU typedMessage = ref
|
|
4788
|
+
ref TU typedMessage = ref DxUnsafe.As<TMessage, TU>(ref message);
|
|
5160
4789
|
List<FastHandlerWithContext<TU>> handlers = GetOrAddNewHandlerStack(
|
|
5161
4790
|
cache,
|
|
5162
4791
|
emissionId
|
|
@@ -5172,36 +4801,76 @@ namespace DxMessaging.Core
|
|
|
5172
4801
|
case 2:
|
|
5173
4802
|
{
|
|
5174
4803
|
handlers[0](ref context, ref typedMessage);
|
|
4804
|
+
if (handlers.Count < 2)
|
|
4805
|
+
{
|
|
4806
|
+
return;
|
|
4807
|
+
}
|
|
5175
4808
|
handlers[1](ref context, ref typedMessage);
|
|
5176
4809
|
return;
|
|
5177
4810
|
}
|
|
5178
4811
|
case 3:
|
|
5179
4812
|
{
|
|
5180
4813
|
handlers[0](ref context, ref typedMessage);
|
|
4814
|
+
if (handlers.Count < 2)
|
|
4815
|
+
{
|
|
4816
|
+
return;
|
|
4817
|
+
}
|
|
5181
4818
|
handlers[1](ref context, ref typedMessage);
|
|
4819
|
+
if (handlers.Count < 3)
|
|
4820
|
+
{
|
|
4821
|
+
return;
|
|
4822
|
+
}
|
|
5182
4823
|
handlers[2](ref context, ref typedMessage);
|
|
5183
4824
|
return;
|
|
5184
4825
|
}
|
|
5185
4826
|
case 4:
|
|
5186
4827
|
{
|
|
5187
4828
|
handlers[0](ref context, ref typedMessage);
|
|
4829
|
+
if (handlers.Count < 2)
|
|
4830
|
+
{
|
|
4831
|
+
return;
|
|
4832
|
+
}
|
|
5188
4833
|
handlers[1](ref context, ref typedMessage);
|
|
4834
|
+
if (handlers.Count < 3)
|
|
4835
|
+
{
|
|
4836
|
+
return;
|
|
4837
|
+
}
|
|
5189
4838
|
handlers[2](ref context, ref typedMessage);
|
|
4839
|
+
if (handlers.Count < 4)
|
|
4840
|
+
{
|
|
4841
|
+
return;
|
|
4842
|
+
}
|
|
5190
4843
|
handlers[3](ref context, ref typedMessage);
|
|
5191
4844
|
return;
|
|
5192
4845
|
}
|
|
5193
4846
|
case 5:
|
|
5194
4847
|
{
|
|
5195
4848
|
handlers[0](ref context, ref typedMessage);
|
|
4849
|
+
if (handlers.Count < 2)
|
|
4850
|
+
{
|
|
4851
|
+
return;
|
|
4852
|
+
}
|
|
5196
4853
|
handlers[1](ref context, ref typedMessage);
|
|
4854
|
+
if (handlers.Count < 3)
|
|
4855
|
+
{
|
|
4856
|
+
return;
|
|
4857
|
+
}
|
|
5197
4858
|
handlers[2](ref context, ref typedMessage);
|
|
4859
|
+
if (handlers.Count < 4)
|
|
4860
|
+
{
|
|
4861
|
+
return;
|
|
4862
|
+
}
|
|
5198
4863
|
handlers[3](ref context, ref typedMessage);
|
|
4864
|
+
if (handlers.Count < 5)
|
|
4865
|
+
{
|
|
4866
|
+
return;
|
|
4867
|
+
}
|
|
5199
4868
|
handlers[4](ref context, ref typedMessage);
|
|
5200
4869
|
return;
|
|
5201
4870
|
}
|
|
5202
4871
|
}
|
|
5203
4872
|
|
|
5204
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
4873
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
5205
4874
|
{
|
|
5206
4875
|
handlers[i](ref context, ref typedMessage);
|
|
5207
4876
|
}
|
|
@@ -5278,7 +4947,7 @@ namespace DxMessaging.Core
|
|
|
5278
4947
|
}
|
|
5279
4948
|
|
|
5280
4949
|
List<Action<T>> handlers = GetOrAddNewHandlerStack(cache, emissionId);
|
|
5281
|
-
ref T typedMessage = ref
|
|
4950
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
5282
4951
|
int handlersCount = handlers.Count;
|
|
5283
4952
|
switch (handlersCount)
|
|
5284
4953
|
{
|
|
@@ -5290,36 +4959,76 @@ namespace DxMessaging.Core
|
|
|
5290
4959
|
case 2:
|
|
5291
4960
|
{
|
|
5292
4961
|
handlers[0](typedMessage);
|
|
4962
|
+
if (handlers.Count < 2)
|
|
4963
|
+
{
|
|
4964
|
+
return;
|
|
4965
|
+
}
|
|
5293
4966
|
handlers[1](typedMessage);
|
|
5294
4967
|
return;
|
|
5295
4968
|
}
|
|
5296
4969
|
case 3:
|
|
5297
4970
|
{
|
|
5298
4971
|
handlers[0](typedMessage);
|
|
4972
|
+
if (handlers.Count < 2)
|
|
4973
|
+
{
|
|
4974
|
+
return;
|
|
4975
|
+
}
|
|
5299
4976
|
handlers[1](typedMessage);
|
|
4977
|
+
if (handlers.Count < 3)
|
|
4978
|
+
{
|
|
4979
|
+
return;
|
|
4980
|
+
}
|
|
5300
4981
|
handlers[2](typedMessage);
|
|
5301
4982
|
return;
|
|
5302
4983
|
}
|
|
5303
4984
|
case 4:
|
|
5304
4985
|
{
|
|
5305
4986
|
handlers[0](typedMessage);
|
|
4987
|
+
if (handlers.Count < 2)
|
|
4988
|
+
{
|
|
4989
|
+
return;
|
|
4990
|
+
}
|
|
5306
4991
|
handlers[1](typedMessage);
|
|
4992
|
+
if (handlers.Count < 3)
|
|
4993
|
+
{
|
|
4994
|
+
return;
|
|
4995
|
+
}
|
|
5307
4996
|
handlers[2](typedMessage);
|
|
4997
|
+
if (handlers.Count < 4)
|
|
4998
|
+
{
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5308
5001
|
handlers[3](typedMessage);
|
|
5309
5002
|
return;
|
|
5310
5003
|
}
|
|
5311
5004
|
case 5:
|
|
5312
5005
|
{
|
|
5313
5006
|
handlers[0](typedMessage);
|
|
5007
|
+
if (handlers.Count < 2)
|
|
5008
|
+
{
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5314
5011
|
handlers[1](typedMessage);
|
|
5012
|
+
if (handlers.Count < 3)
|
|
5013
|
+
{
|
|
5014
|
+
return;
|
|
5015
|
+
}
|
|
5315
5016
|
handlers[2](typedMessage);
|
|
5017
|
+
if (handlers.Count < 4)
|
|
5018
|
+
{
|
|
5019
|
+
return;
|
|
5020
|
+
}
|
|
5316
5021
|
handlers[3](typedMessage);
|
|
5022
|
+
if (handlers.Count < 5)
|
|
5023
|
+
{
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5317
5026
|
handlers[4](typedMessage);
|
|
5318
5027
|
return;
|
|
5319
5028
|
}
|
|
5320
5029
|
}
|
|
5321
5030
|
|
|
5322
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
5031
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
5323
5032
|
{
|
|
5324
5033
|
handlers[i](typedMessage);
|
|
5325
5034
|
}
|
|
@@ -5344,7 +5053,7 @@ namespace DxMessaging.Core
|
|
|
5344
5053
|
}
|
|
5345
5054
|
|
|
5346
5055
|
List<Action<T>> handlers = GetOrAddNewHandlerStack(cache, emissionId);
|
|
5347
|
-
ref T typedMessage = ref
|
|
5056
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
5348
5057
|
int handlersCount = handlers.Count;
|
|
5349
5058
|
switch (handlersCount)
|
|
5350
5059
|
{
|
|
@@ -5356,36 +5065,76 @@ namespace DxMessaging.Core
|
|
|
5356
5065
|
case 2:
|
|
5357
5066
|
{
|
|
5358
5067
|
handlers[0](typedMessage);
|
|
5068
|
+
if (handlers.Count < 2)
|
|
5069
|
+
{
|
|
5070
|
+
return;
|
|
5071
|
+
}
|
|
5359
5072
|
handlers[1](typedMessage);
|
|
5360
5073
|
return;
|
|
5361
5074
|
}
|
|
5362
5075
|
case 3:
|
|
5363
5076
|
{
|
|
5364
5077
|
handlers[0](typedMessage);
|
|
5078
|
+
if (handlers.Count < 2)
|
|
5079
|
+
{
|
|
5080
|
+
return;
|
|
5081
|
+
}
|
|
5365
5082
|
handlers[1](typedMessage);
|
|
5083
|
+
if (handlers.Count < 3)
|
|
5084
|
+
{
|
|
5085
|
+
return;
|
|
5086
|
+
}
|
|
5366
5087
|
handlers[2](typedMessage);
|
|
5367
5088
|
return;
|
|
5368
5089
|
}
|
|
5369
5090
|
case 4:
|
|
5370
5091
|
{
|
|
5371
5092
|
handlers[0](typedMessage);
|
|
5093
|
+
if (handlers.Count < 2)
|
|
5094
|
+
{
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
5372
5097
|
handlers[1](typedMessage);
|
|
5098
|
+
if (handlers.Count < 3)
|
|
5099
|
+
{
|
|
5100
|
+
return;
|
|
5101
|
+
}
|
|
5373
5102
|
handlers[2](typedMessage);
|
|
5103
|
+
if (handlers.Count < 4)
|
|
5104
|
+
{
|
|
5105
|
+
return;
|
|
5106
|
+
}
|
|
5374
5107
|
handlers[3](typedMessage);
|
|
5375
5108
|
return;
|
|
5376
5109
|
}
|
|
5377
5110
|
case 5:
|
|
5378
5111
|
{
|
|
5379
5112
|
handlers[0](typedMessage);
|
|
5113
|
+
if (handlers.Count < 2)
|
|
5114
|
+
{
|
|
5115
|
+
return;
|
|
5116
|
+
}
|
|
5380
5117
|
handlers[1](typedMessage);
|
|
5118
|
+
if (handlers.Count < 3)
|
|
5119
|
+
{
|
|
5120
|
+
return;
|
|
5121
|
+
}
|
|
5381
5122
|
handlers[2](typedMessage);
|
|
5123
|
+
if (handlers.Count < 4)
|
|
5124
|
+
{
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5382
5127
|
handlers[3](typedMessage);
|
|
5128
|
+
if (handlers.Count < 5)
|
|
5129
|
+
{
|
|
5130
|
+
return;
|
|
5131
|
+
}
|
|
5383
5132
|
handlers[4](typedMessage);
|
|
5384
5133
|
return;
|
|
5385
5134
|
}
|
|
5386
5135
|
}
|
|
5387
5136
|
|
|
5388
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
5137
|
+
for (int i = 0; i < handlersCount && i < handlers.Count; ++i)
|
|
5389
5138
|
{
|
|
5390
5139
|
handlers[i](typedMessage);
|
|
5391
5140
|
}
|
|
@@ -5417,7 +5166,7 @@ namespace DxMessaging.Core
|
|
|
5417
5166
|
cache,
|
|
5418
5167
|
emissionId
|
|
5419
5168
|
);
|
|
5420
|
-
ref T typedMessage = ref
|
|
5169
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
5421
5170
|
int handlersCount = typedHandlers.Count;
|
|
5422
5171
|
switch (handlersCount)
|
|
5423
5172
|
{
|
|
@@ -5429,36 +5178,76 @@ namespace DxMessaging.Core
|
|
|
5429
5178
|
case 2:
|
|
5430
5179
|
{
|
|
5431
5180
|
typedHandlers[0](context, typedMessage);
|
|
5181
|
+
if (typedHandlers.Count < 2)
|
|
5182
|
+
{
|
|
5183
|
+
return;
|
|
5184
|
+
}
|
|
5432
5185
|
typedHandlers[1](context, typedMessage);
|
|
5433
5186
|
return;
|
|
5434
5187
|
}
|
|
5435
5188
|
case 3:
|
|
5436
5189
|
{
|
|
5437
5190
|
typedHandlers[0](context, typedMessage);
|
|
5191
|
+
if (typedHandlers.Count < 2)
|
|
5192
|
+
{
|
|
5193
|
+
return;
|
|
5194
|
+
}
|
|
5438
5195
|
typedHandlers[1](context, typedMessage);
|
|
5196
|
+
if (typedHandlers.Count < 3)
|
|
5197
|
+
{
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
5439
5200
|
typedHandlers[2](context, typedMessage);
|
|
5440
5201
|
return;
|
|
5441
5202
|
}
|
|
5442
5203
|
case 4:
|
|
5443
5204
|
{
|
|
5444
5205
|
typedHandlers[0](context, typedMessage);
|
|
5206
|
+
if (typedHandlers.Count < 2)
|
|
5207
|
+
{
|
|
5208
|
+
return;
|
|
5209
|
+
}
|
|
5445
5210
|
typedHandlers[1](context, typedMessage);
|
|
5211
|
+
if (typedHandlers.Count < 3)
|
|
5212
|
+
{
|
|
5213
|
+
return;
|
|
5214
|
+
}
|
|
5446
5215
|
typedHandlers[2](context, typedMessage);
|
|
5216
|
+
if (typedHandlers.Count < 4)
|
|
5217
|
+
{
|
|
5218
|
+
return;
|
|
5219
|
+
}
|
|
5447
5220
|
typedHandlers[3](context, typedMessage);
|
|
5448
5221
|
return;
|
|
5449
5222
|
}
|
|
5450
5223
|
case 5:
|
|
5451
5224
|
{
|
|
5452
5225
|
typedHandlers[0](context, typedMessage);
|
|
5226
|
+
if (typedHandlers.Count < 2)
|
|
5227
|
+
{
|
|
5228
|
+
return;
|
|
5229
|
+
}
|
|
5453
5230
|
typedHandlers[1](context, typedMessage);
|
|
5231
|
+
if (typedHandlers.Count < 3)
|
|
5232
|
+
{
|
|
5233
|
+
return;
|
|
5234
|
+
}
|
|
5454
5235
|
typedHandlers[2](context, typedMessage);
|
|
5236
|
+
if (typedHandlers.Count < 4)
|
|
5237
|
+
{
|
|
5238
|
+
return;
|
|
5239
|
+
}
|
|
5455
5240
|
typedHandlers[3](context, typedMessage);
|
|
5241
|
+
if (typedHandlers.Count < 5)
|
|
5242
|
+
{
|
|
5243
|
+
return;
|
|
5244
|
+
}
|
|
5456
5245
|
typedHandlers[4](context, typedMessage);
|
|
5457
5246
|
return;
|
|
5458
5247
|
}
|
|
5459
5248
|
}
|
|
5460
5249
|
|
|
5461
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
5250
|
+
for (int i = 0; i < handlersCount && i < typedHandlers.Count; ++i)
|
|
5462
5251
|
{
|
|
5463
5252
|
typedHandlers[i](context, typedMessage);
|
|
5464
5253
|
}
|
|
@@ -5492,7 +5281,7 @@ namespace DxMessaging.Core
|
|
|
5492
5281
|
cache,
|
|
5493
5282
|
emissionId
|
|
5494
5283
|
);
|
|
5495
|
-
ref T typedMessage = ref
|
|
5284
|
+
ref T typedMessage = ref DxUnsafe.As<TMessage, T>(ref message);
|
|
5496
5285
|
int handlersCount = typedHandlers.Count;
|
|
5497
5286
|
switch (handlersCount)
|
|
5498
5287
|
{
|
|
@@ -5504,60 +5293,124 @@ namespace DxMessaging.Core
|
|
|
5504
5293
|
case 2:
|
|
5505
5294
|
{
|
|
5506
5295
|
typedHandlers[0](context, typedMessage);
|
|
5296
|
+
if (typedHandlers.Count < 2)
|
|
5297
|
+
{
|
|
5298
|
+
return;
|
|
5299
|
+
}
|
|
5507
5300
|
typedHandlers[1](context, typedMessage);
|
|
5508
5301
|
return;
|
|
5509
5302
|
}
|
|
5510
5303
|
case 3:
|
|
5511
5304
|
{
|
|
5512
5305
|
typedHandlers[0](context, typedMessage);
|
|
5306
|
+
if (typedHandlers.Count < 2)
|
|
5307
|
+
{
|
|
5308
|
+
return;
|
|
5309
|
+
}
|
|
5513
5310
|
typedHandlers[1](context, typedMessage);
|
|
5311
|
+
if (typedHandlers.Count < 3)
|
|
5312
|
+
{
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5514
5315
|
typedHandlers[2](context, typedMessage);
|
|
5515
5316
|
return;
|
|
5516
5317
|
}
|
|
5517
5318
|
case 4:
|
|
5518
5319
|
{
|
|
5519
5320
|
typedHandlers[0](context, typedMessage);
|
|
5321
|
+
if (typedHandlers.Count < 2)
|
|
5322
|
+
{
|
|
5323
|
+
return;
|
|
5324
|
+
}
|
|
5520
5325
|
typedHandlers[1](context, typedMessage);
|
|
5326
|
+
if (typedHandlers.Count < 3)
|
|
5327
|
+
{
|
|
5328
|
+
return;
|
|
5329
|
+
}
|
|
5521
5330
|
typedHandlers[2](context, typedMessage);
|
|
5331
|
+
if (typedHandlers.Count < 4)
|
|
5332
|
+
{
|
|
5333
|
+
return;
|
|
5334
|
+
}
|
|
5522
5335
|
typedHandlers[3](context, typedMessage);
|
|
5523
5336
|
return;
|
|
5524
5337
|
}
|
|
5525
5338
|
case 5:
|
|
5526
5339
|
{
|
|
5527
5340
|
typedHandlers[0](context, typedMessage);
|
|
5341
|
+
if (typedHandlers.Count < 2)
|
|
5342
|
+
{
|
|
5343
|
+
return;
|
|
5344
|
+
}
|
|
5528
5345
|
typedHandlers[1](context, typedMessage);
|
|
5346
|
+
if (typedHandlers.Count < 3)
|
|
5347
|
+
{
|
|
5348
|
+
return;
|
|
5349
|
+
}
|
|
5529
5350
|
typedHandlers[2](context, typedMessage);
|
|
5351
|
+
if (typedHandlers.Count < 4)
|
|
5352
|
+
{
|
|
5353
|
+
return;
|
|
5354
|
+
}
|
|
5530
5355
|
typedHandlers[3](context, typedMessage);
|
|
5356
|
+
if (typedHandlers.Count < 5)
|
|
5357
|
+
{
|
|
5358
|
+
return;
|
|
5359
|
+
}
|
|
5531
5360
|
typedHandlers[4](context, typedMessage);
|
|
5532
5361
|
return;
|
|
5533
5362
|
}
|
|
5534
5363
|
}
|
|
5535
5364
|
|
|
5536
|
-
for (int i = 0; i < handlersCount; ++i)
|
|
5365
|
+
for (int i = 0; i < handlersCount && i < typedHandlers.Count; ++i)
|
|
5537
5366
|
{
|
|
5538
5367
|
typedHandlers[i](context, typedMessage);
|
|
5539
5368
|
}
|
|
5540
5369
|
}
|
|
5541
5370
|
|
|
5371
|
+
// Mid-dispatch clear contract: the List returned here is the LIVE
|
|
5372
|
+
// cache.cache list, not a copy. IHandlerActionCache.Reset() (bus
|
|
5373
|
+
// reset / sweep eviction) clears it IN PLACE, so every dispatch
|
|
5374
|
+
// loop that indexes the returned list re-checks list.Count before
|
|
5375
|
+
// each invocation past the first (and the >5 fallback loops bound
|
|
5376
|
+
// on the live Count). A reset fired from inside a handler then
|
|
5377
|
+
// cleanly stops the in-flight bucket: no peer delegate runs and
|
|
5378
|
+
// nothing throws. The re-check is a single inlined List.Count
|
|
5379
|
+
// field read on data already in cache, so steady-state dispatch
|
|
5380
|
+
// cost is unchanged.
|
|
5542
5381
|
internal static List<TU> GetOrAddNewHandlerStack<TU>(
|
|
5543
5382
|
HandlerActionCache<TU> actionCache,
|
|
5544
5383
|
long emissionId
|
|
5545
5384
|
)
|
|
5546
5385
|
{
|
|
5386
|
+
DebugAssertInsertionOrderInSync(actionCache);
|
|
5547
5387
|
if (actionCache.lastSeenEmissionId != emissionId)
|
|
5548
5388
|
{
|
|
5549
5389
|
if (actionCache.version != actionCache.lastSeenVersion)
|
|
5550
5390
|
{
|
|
5391
|
+
// Rebuild the dispatch snapshot from insertionOrder, NOT from
|
|
5392
|
+
// the entries dictionary: dictionary enumeration order permutes
|
|
5393
|
+
// after Remove/Add churn (freed slots are reused LIFO), while
|
|
5394
|
+
// insertionOrder preserves the documented first-registration
|
|
5395
|
+
// order for equal-priority handlers. This branch only runs on
|
|
5396
|
+
// registration churn (version bump), never on steady-state
|
|
5397
|
+
// dispatch, and allocates nothing (the pooled cache list is
|
|
5398
|
+
// cleared and refilled in place).
|
|
5551
5399
|
List<TU> list = actionCache.cache;
|
|
5552
5400
|
list.Clear();
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
HandlerActionCache<TU>.Entry
|
|
5557
|
-
> kvp in actionCache.entries
|
|
5558
|
-
)
|
|
5401
|
+
List<TU> orderedHandlers = actionCache.insertionOrder;
|
|
5402
|
+
int orderedCount = orderedHandlers.Count;
|
|
5403
|
+
for (int i = 0; i < orderedCount; ++i)
|
|
5559
5404
|
{
|
|
5560
|
-
|
|
5405
|
+
if (
|
|
5406
|
+
actionCache.entries.TryGetValue(
|
|
5407
|
+
orderedHandlers[i],
|
|
5408
|
+
out HandlerActionCache<TU>.Entry entry
|
|
5409
|
+
)
|
|
5410
|
+
)
|
|
5411
|
+
{
|
|
5412
|
+
list.Add(entry.handler);
|
|
5413
|
+
}
|
|
5561
5414
|
}
|
|
5562
5415
|
actionCache.lastSeenVersion = actionCache.version;
|
|
5563
5416
|
}
|
|
@@ -5566,37 +5419,25 @@ namespace DxMessaging.Core
|
|
|
5566
5419
|
return actionCache.cache;
|
|
5567
5420
|
}
|
|
5568
5421
|
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
)
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
)
|
|
5580
|
-
{
|
|
5581
|
-
cache.prefreezeInvocationCount++;
|
|
5582
|
-
_ = GetOrAddNewHandlerStack(cache, emissionId);
|
|
5583
|
-
}
|
|
5584
|
-
}
|
|
5585
|
-
|
|
5586
|
-
private static void PrefreezeHandlersForEmission<THandler>(
|
|
5587
|
-
Dictionary<int, HandlerActionCache<THandler>> handlers,
|
|
5588
|
-
int priority,
|
|
5589
|
-
long emissionId
|
|
5422
|
+
// Asserts insertionOrder stays in lockstep with the entries
|
|
5423
|
+
// dictionary at every dispatch-snapshot read. Drift indicates a
|
|
5424
|
+
// mutation site of HandlerActionCache.entries that forgot to
|
|
5425
|
+
// mirror the change into insertionOrder (AddHandler* family,
|
|
5426
|
+
// deregistration closures, IHandlerActionCache.Reset). Stripped
|
|
5427
|
+
// in Release builds via [Conditional("DEBUG")] -- zero hot-path
|
|
5428
|
+
// cost.
|
|
5429
|
+
[Conditional("DEBUG")]
|
|
5430
|
+
private static void DebugAssertInsertionOrderInSync<TU>(
|
|
5431
|
+
HandlerActionCache<TU> actionCache
|
|
5590
5432
|
)
|
|
5591
5433
|
{
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
}
|
|
5434
|
+
System.Diagnostics.Debug.Assert(
|
|
5435
|
+
actionCache.insertionOrder.Count == actionCache.entries.Count,
|
|
5436
|
+
"HandlerActionCache.insertionOrder must mirror entries: every first "
|
|
5437
|
+
+ "registration appends and every final deregistration removes. A "
|
|
5438
|
+
+ "count mismatch means a mutation site skipped the insertionOrder "
|
|
5439
|
+
+ "update and same-priority dispatch order is no longer trustworthy."
|
|
5440
|
+
);
|
|
5600
5441
|
}
|
|
5601
5442
|
|
|
5602
5443
|
private static Action AddHandler<TU>(
|
|
@@ -5632,6 +5473,10 @@ namespace DxMessaging.Core
|
|
|
5632
5473
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
5633
5474
|
|
|
5634
5475
|
cache.entries[originalHandler] = entry;
|
|
5476
|
+
if (firstRegistration)
|
|
5477
|
+
{
|
|
5478
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5479
|
+
}
|
|
5635
5480
|
cache.version++;
|
|
5636
5481
|
if (firstRegistration)
|
|
5637
5482
|
{
|
|
@@ -5682,6 +5527,7 @@ namespace DxMessaging.Core
|
|
|
5682
5527
|
if (localEntry.count <= 1)
|
|
5683
5528
|
{
|
|
5684
5529
|
_ = localCache.entries.Remove(originalHandler);
|
|
5530
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
5685
5531
|
localCache.version++;
|
|
5686
5532
|
localSlot.liveCount--;
|
|
5687
5533
|
return;
|
|
@@ -5744,6 +5590,10 @@ namespace DxMessaging.Core
|
|
|
5744
5590
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
5745
5591
|
|
|
5746
5592
|
cache.entries[originalHandler] = entry;
|
|
5593
|
+
if (firstRegistration)
|
|
5594
|
+
{
|
|
5595
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5596
|
+
}
|
|
5747
5597
|
cache.version++;
|
|
5748
5598
|
|
|
5749
5599
|
Dictionary<
|
|
@@ -5782,6 +5632,7 @@ namespace DxMessaging.Core
|
|
|
5782
5632
|
if (localEntry.count <= 1)
|
|
5783
5633
|
{
|
|
5784
5634
|
_ = localCache.entries.Remove(originalHandler);
|
|
5635
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
5785
5636
|
localCache.version++;
|
|
5786
5637
|
if (localCache.entries.Count == 0)
|
|
5787
5638
|
{
|
|
@@ -5829,6 +5680,10 @@ namespace DxMessaging.Core
|
|
|
5829
5680
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
5830
5681
|
|
|
5831
5682
|
cache.entries[originalHandler] = entry;
|
|
5683
|
+
if (firstRegistration)
|
|
5684
|
+
{
|
|
5685
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5686
|
+
}
|
|
5832
5687
|
cache.version++;
|
|
5833
5688
|
|
|
5834
5689
|
HandlerActionCache<TU> localCache = cache;
|
|
@@ -5852,6 +5707,7 @@ namespace DxMessaging.Core
|
|
|
5852
5707
|
if (localEntry.count <= 1)
|
|
5853
5708
|
{
|
|
5854
5709
|
_ = localCache.entries.Remove(originalHandler);
|
|
5710
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
5855
5711
|
localCache.version++;
|
|
5856
5712
|
return;
|
|
5857
5713
|
}
|
|
@@ -5897,6 +5753,10 @@ namespace DxMessaging.Core
|
|
|
5897
5753
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
5898
5754
|
|
|
5899
5755
|
cache.entries[originalHandler] = entry;
|
|
5756
|
+
if (firstRegistration)
|
|
5757
|
+
{
|
|
5758
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5759
|
+
}
|
|
5900
5760
|
cache.version++;
|
|
5901
5761
|
|
|
5902
5762
|
Dictionary<int, HandlerActionCache<TU>> localHandlers = handlers;
|
|
@@ -5925,6 +5785,7 @@ namespace DxMessaging.Core
|
|
|
5925
5785
|
if (localEntry.count <= 1)
|
|
5926
5786
|
{
|
|
5927
5787
|
_ = localCache.entries.Remove(originalHandler);
|
|
5788
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
5928
5789
|
localCache.version++;
|
|
5929
5790
|
if (localCache.entries.Count == 0)
|
|
5930
5791
|
{
|
|
@@ -5946,13 +5807,17 @@ namespace DxMessaging.Core
|
|
|
5946
5807
|
// Variant of AddHandler that preserves the priority key in the dictionary when the last entry is removed.
|
|
5947
5808
|
// This ensures that during an in-flight emission (where handler stacks are already frozen),
|
|
5948
5809
|
// subsequent removals do not cause lookups to fail for the current pass.
|
|
5810
|
+
// `flatInvoker` carries the pre-resolved flat-dispatch invoker for
|
|
5811
|
+
// registrations the bus-side flat snapshot consumes (untargeted
|
|
5812
|
+
// handle/post default handlers); see HandlerActionCache.Entry.flatInvoker.
|
|
5949
5813
|
private Action AddHandlerPreservingPriorityKey<TU>(
|
|
5950
5814
|
Dictionary<int, IHandlerActionCache> handlers,
|
|
5951
5815
|
TU originalHandler,
|
|
5952
5816
|
TU augmentedHandler,
|
|
5953
5817
|
Action deregistration,
|
|
5954
5818
|
int priority,
|
|
5955
|
-
IMessageBus messageBus
|
|
5819
|
+
IMessageBus messageBus,
|
|
5820
|
+
object flatInvoker = null
|
|
5956
5821
|
)
|
|
5957
5822
|
{
|
|
5958
5823
|
if (
|
|
@@ -5976,10 +5841,18 @@ namespace DxMessaging.Core
|
|
|
5976
5841
|
|
|
5977
5842
|
bool firstRegistration = entry.count == 0;
|
|
5978
5843
|
entry = firstRegistration
|
|
5979
|
-
? new HandlerActionCache<TU>.Entry(augmentedHandler, 1)
|
|
5980
|
-
: new HandlerActionCache<TU>.Entry(
|
|
5844
|
+
? new HandlerActionCache<TU>.Entry(augmentedHandler, 1, flatInvoker)
|
|
5845
|
+
: new HandlerActionCache<TU>.Entry(
|
|
5846
|
+
entry.handler,
|
|
5847
|
+
entry.count + 1,
|
|
5848
|
+
entry.flatInvoker
|
|
5849
|
+
);
|
|
5981
5850
|
|
|
5982
5851
|
cache.entries[originalHandler] = entry;
|
|
5852
|
+
if (firstRegistration)
|
|
5853
|
+
{
|
|
5854
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5855
|
+
}
|
|
5983
5856
|
cache.version++;
|
|
5984
5857
|
TypedSlot<T> slot = FindPrioritySlot(handlers);
|
|
5985
5858
|
if (slot != null)
|
|
@@ -6055,6 +5928,7 @@ namespace DxMessaging.Core
|
|
|
6055
5928
|
if (localEntry.count <= 1)
|
|
6056
5929
|
{
|
|
6057
5930
|
_ = localCache.entries.Remove(originalHandler);
|
|
5931
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
6058
5932
|
localCache.version++;
|
|
6059
5933
|
if (localSlot != null)
|
|
6060
5934
|
{
|
|
@@ -6067,7 +5941,8 @@ namespace DxMessaging.Core
|
|
|
6067
5941
|
|
|
6068
5942
|
localEntry = new HandlerActionCache<TU>.Entry(
|
|
6069
5943
|
localEntry.handler,
|
|
6070
|
-
localEntry.count - 1
|
|
5944
|
+
localEntry.count - 1,
|
|
5945
|
+
localEntry.flatInvoker
|
|
6071
5946
|
);
|
|
6072
5947
|
|
|
6073
5948
|
localCache.entries[originalHandler] = localEntry;
|
|
@@ -6107,6 +5982,10 @@ namespace DxMessaging.Core
|
|
|
6107
5982
|
: new HandlerActionCache<TU>.Entry(entry.handler, entry.count + 1);
|
|
6108
5983
|
|
|
6109
5984
|
cache.entries[originalHandler] = entry;
|
|
5985
|
+
if (firstRegistration)
|
|
5986
|
+
{
|
|
5987
|
+
cache.insertionOrder.Add(originalHandler);
|
|
5988
|
+
}
|
|
6110
5989
|
cache.version++;
|
|
6111
5990
|
|
|
6112
5991
|
Dictionary<int, HandlerActionCache<TU>> localHandlers = handlers;
|
|
@@ -6135,6 +6014,7 @@ namespace DxMessaging.Core
|
|
|
6135
6014
|
if (localEntry.count <= 1)
|
|
6136
6015
|
{
|
|
6137
6016
|
_ = localCache.entries.Remove(originalHandler);
|
|
6017
|
+
_ = localCache.insertionOrder.Remove(originalHandler);
|
|
6138
6018
|
localCache.version++;
|
|
6139
6019
|
// Intentionally DO NOT remove the priority key here to preserve
|
|
6140
6020
|
// the cache handle during an in-flight emission.
|