com.wallstop-studios.dxmessaging 3.0.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +497 -2
- package/Editor/Analyzers/BaseCallLogMessageParser.cs.meta +3 -3
- package/Editor/Analyzers/BaseCallReportAggregator.cs.meta +3 -3
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs +69 -62
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs.meta +3 -3
- package/Editor/AssemblyInfo.cs.meta +9 -1
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs.meta +3 -3
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs +24 -15
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs.meta +3 -3
- 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/DxMessagingMenu.cs.meta +3 -3
- package/Editor/DxMessagingSceneBuildProcessor.cs.meta +3 -3
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +137 -15
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs.meta +3 -3
- 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 +539 -304
- 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/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
- package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.dll.meta +3 -3
- package/{Editor → Runtime}/Analyzers/System.Collections.Immutable.dll.meta +3 -3
- package/{Editor → Runtime}/Analyzers/System.Reflection.Metadata.dll.meta +3 -3
- package/{Editor → Runtime}/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +3 -3
- package/Runtime/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- package/Runtime/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +46 -0
- package/Runtime/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- package/{Editor → Runtime}/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +2 -2
- package/Runtime/Analyzers.meta +8 -0
- 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/DxIgnoreMissingBaseCallAttribute.cs.meta +3 -3
- 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/DxMessagingStaticState.cs.meta +3 -3
- 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/MessageBusExtensions.cs.meta +3 -3
- package/Runtime/Core/Extensions/MessageExtensions.cs +0 -60
- package/Runtime/Core/Extensions/MessageExtensions.cs.meta +3 -3
- package/Runtime/Core/Helper/MessageCache.cs.meta +9 -1
- package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +9 -1
- package/Runtime/Core/IMessage.cs.meta +3 -3
- package/Runtime/Core/InstanceId.cs +25 -1
- package/Runtime/Core/InstanceId.cs.meta +3 -3
- 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 +47 -21
- package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +3 -3
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageBus.cs +75 -40
- package/Runtime/Core/MessageBus/IMessageBus.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +3 -3
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +1 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +3 -3
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs +7 -6
- package/Runtime/Core/MessageBus/MessageBus.cs +2864 -3413
- package/Runtime/Core/MessageBus/MessageBus.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessageBusRegistration.cs +207 -0
- package/Runtime/Core/MessageBus/MessageBusRegistration.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +187 -14
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +3 -3
- package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +3 -3
- package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +3 -3
- package/Runtime/Core/MessageHandler.cs +2206 -1510
- package/Runtime/Core/MessageHandler.cs.meta +3 -3
- package/Runtime/Core/MessageRegistrationHandle.cs.meta +3 -3
- package/Runtime/Core/MessageRegistrationToken.cs +1667 -812
- package/Runtime/Core/MessageRegistrationToken.cs.meta +3 -3
- package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +9 -1
- package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/ITargetedMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +9 -1
- package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +3 -3
- package/Runtime/Core/Messages/StringMessage.cs.meta +9 -1
- package/Runtime/Core/MessagingDebug.cs.meta +3 -3
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +3 -3
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +3 -3
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +3 -3
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +3 -3
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +9 -1
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +3 -3
- package/Runtime/Unity/MessageAwareComponent.cs +46 -1
- package/Runtime/Unity/MessageAwareComponent.cs.meta +3 -3
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +3 -3
- package/Runtime/Unity/MessagingComponent.cs +43 -10
- package/Runtime/Unity/MessagingComponent.cs.meta +3 -3
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +3 -3
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +3 -3
- package/Runtime/WallstopStudios.DxMessaging.asmdef +1 -1
- package/Samples~/DI/README.md +7 -7
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +3 -3
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +3 -3
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +3 -3
- package/Samples~/Mini Combat/Boot.cs.meta +3 -3
- package/Samples~/Mini Combat/Enemy.cs.meta +3 -3
- package/Samples~/Mini Combat/Messages.cs.meta +3 -3
- package/Samples~/Mini Combat/Player.cs.meta +3 -3
- package/Samples~/Mini Combat/UIOverlay.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/Messages.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +3 -3
- package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +3 -3
- package/SourceGenerators/Directory.Build.props +50 -3
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +96 -63
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +3 -3
- 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 +40 -46
- package/SourceGenerators/global.json +7 -0
- package/SourceGenerators/global.json.meta +7 -0
- package/package.json +30 -40
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +0 -33
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- package/Runtime/Core/Internal/TypedDispatchLinkIndex.cs +0 -51
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Collections.Immutable.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Reflection.Metadata.dll +0 -0
- /package/{Editor → Runtime}/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
namespace DxMessaging.Core.MessageBus
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Runtime.CompilerServices;
|
|
5
|
+
|
|
6
|
+
/// <summary>
|
|
7
|
+
/// Opaque subscription handle returned by the <see cref="IMessageBus"/> registration
|
|
8
|
+
/// methods (replacing the deregistration <see cref="Action"/> returned prior to v4).
|
|
9
|
+
/// </summary>
|
|
10
|
+
/// <remarks>
|
|
11
|
+
/// <para>
|
|
12
|
+
/// Hand the handle back to <see cref="IMessageBus.Deregister{T}"/> with the SAME
|
|
13
|
+
/// <c>T</c> you registered with to undo the registration. It is an opaque value token:
|
|
14
|
+
/// copy it freely, but do NOT inspect or persist its internals. Handles are
|
|
15
|
+
/// process-local, single-thread, and NOT serializable; a handle is meaningless after a
|
|
16
|
+
/// domain reload (its captured generation no longer matches, so deregistration becomes a
|
|
17
|
+
/// silent no-op) and is not portable across <see cref="IMessageBus"/> implementations.
|
|
18
|
+
/// </para>
|
|
19
|
+
/// <para>
|
|
20
|
+
/// The <c>default</c> value is the <see cref="None"/> sentinel; deregistering it is a
|
|
21
|
+
/// no-op. Custom <see cref="IMessageBus"/> implementers that do not wrap
|
|
22
|
+
/// <see cref="MessageBus"/> mint their own handles via the
|
|
23
|
+
/// <see cref="MessageBusRegistration(long, object)"/> constructor and read them back in
|
|
24
|
+
/// their own <see cref="IMessageBus.Deregister{T}"/> override (see <see cref="ExternalId"/>
|
|
25
|
+
/// / <see cref="ExternalState"/>).
|
|
26
|
+
/// </para>
|
|
27
|
+
/// </remarks>
|
|
28
|
+
public readonly struct MessageBusRegistration : IEquatable<MessageBusRegistration>
|
|
29
|
+
{
|
|
30
|
+
/// <summary>
|
|
31
|
+
/// Discriminates which bus store a handle deregisters from. The interceptor stores are
|
|
32
|
+
/// split because all three interceptor registrars log a single
|
|
33
|
+
/// <see cref="RegistrationMethod.Interceptor"/>, so <see cref="method"/> cannot pick
|
|
34
|
+
/// among them; the registering site (which knows the category) stamps the kind.
|
|
35
|
+
/// </summary>
|
|
36
|
+
internal enum Kind : byte
|
|
37
|
+
{
|
|
38
|
+
None = 0,
|
|
39
|
+
Handler,
|
|
40
|
+
UntargetedInterceptor,
|
|
41
|
+
TargetedInterceptor,
|
|
42
|
+
BroadcastInterceptor,
|
|
43
|
+
GlobalAcceptAll,
|
|
44
|
+
External,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// <summary><see cref="Kind.None"/> => an invalid/empty handle; deregistration no-ops.</summary>
|
|
48
|
+
internal readonly Kind kind;
|
|
49
|
+
|
|
50
|
+
/// <summary>
|
|
51
|
+
/// Sink/scalar-vs-keyed discriminator AND the <see cref="RegistrationLog"/> row key for
|
|
52
|
+
/// the <see cref="Kind.Handler"/> shape. Unused (default) for the other kinds.
|
|
53
|
+
/// </summary>
|
|
54
|
+
internal readonly RegistrationMethod method;
|
|
55
|
+
|
|
56
|
+
/// <summary>The priority the handler/interceptor was registered at.</summary>
|
|
57
|
+
internal readonly int priority;
|
|
58
|
+
|
|
59
|
+
/// <summary>The <c>_resetGeneration</c> snapshot (reset/domain-reload guard, all kinds).</summary>
|
|
60
|
+
internal readonly long generation;
|
|
61
|
+
|
|
62
|
+
/// <summary>The <c>_globalSlotSweepGeneration</c> snapshot (<see cref="Kind.GlobalAcceptAll"/> only).</summary>
|
|
63
|
+
internal readonly long sweepGeneration;
|
|
64
|
+
|
|
65
|
+
/// <summary>
|
|
66
|
+
/// A unique per-registration stamp (the bus tick at registration time). It does NOT
|
|
67
|
+
/// participate in deregistration (the sink is re-resolved without it); its sole purpose is
|
|
68
|
+
/// to make two handles from distinct <c>Register*</c> calls compare UNEQUAL even when they
|
|
69
|
+
/// bump the same handler's refcount (same generation/caches/payload/priority/method). This
|
|
70
|
+
/// preserves the pre-v4 semantics where each registration returned a distinct deregistration
|
|
71
|
+
/// delegate, so handles remain safe to store in a set/map keyed by value.
|
|
72
|
+
/// </summary>
|
|
73
|
+
internal readonly long sequence;
|
|
74
|
+
|
|
75
|
+
/// <summary>
|
|
76
|
+
/// The captured identity anchor for the over-deregistration / stale-after-sweep checks:
|
|
77
|
+
/// the per-type <c>HandlerCache</c> (<see cref="Kind.Handler"/>) or the
|
|
78
|
+
/// <c>InterceptorCache</c> (interceptor kinds). Unused for
|
|
79
|
+
/// <see cref="Kind.GlobalAcceptAll"/> (reads the live global slot) and
|
|
80
|
+
/// <see cref="Kind.External"/>.
|
|
81
|
+
/// </summary>
|
|
82
|
+
internal readonly object capturedPrimary;
|
|
83
|
+
|
|
84
|
+
/// <summary>
|
|
85
|
+
/// The keyed (<see cref="Kind.Handler"/> targeted/broadcast) per-type context map captured
|
|
86
|
+
/// by identity; null otherwise.
|
|
87
|
+
/// </summary>
|
|
88
|
+
internal readonly object capturedSecondary;
|
|
89
|
+
|
|
90
|
+
/// <summary>
|
|
91
|
+
/// The deregistration payload: the <see cref="MessageHandler"/>
|
|
92
|
+
/// (<see cref="Kind.Handler"/> / <see cref="Kind.GlobalAcceptAll"/>), the interceptor
|
|
93
|
+
/// delegate (interceptor kinds), or the caller's external state
|
|
94
|
+
/// (<see cref="Kind.External"/>).
|
|
95
|
+
/// </summary>
|
|
96
|
+
internal readonly object payload;
|
|
97
|
+
|
|
98
|
+
/// <summary>
|
|
99
|
+
/// The keyed (<see cref="Kind.Handler"/> targeted/broadcast) target/source; <c>default</c>
|
|
100
|
+
/// otherwise (so no <c>UnityEngine.Object</c> is pinned for non-keyed kinds).
|
|
101
|
+
/// </summary>
|
|
102
|
+
internal readonly InstanceId context;
|
|
103
|
+
|
|
104
|
+
internal MessageBusRegistration(
|
|
105
|
+
Kind kind,
|
|
106
|
+
RegistrationMethod method,
|
|
107
|
+
int priority,
|
|
108
|
+
long generation,
|
|
109
|
+
long sweepGeneration,
|
|
110
|
+
long sequence,
|
|
111
|
+
object capturedPrimary,
|
|
112
|
+
object capturedSecondary,
|
|
113
|
+
object payload,
|
|
114
|
+
InstanceId context
|
|
115
|
+
)
|
|
116
|
+
{
|
|
117
|
+
this.kind = kind;
|
|
118
|
+
this.method = method;
|
|
119
|
+
this.priority = priority;
|
|
120
|
+
this.generation = generation;
|
|
121
|
+
this.sweepGeneration = sweepGeneration;
|
|
122
|
+
this.sequence = sequence;
|
|
123
|
+
this.capturedPrimary = capturedPrimary;
|
|
124
|
+
this.capturedSecondary = capturedSecondary;
|
|
125
|
+
this.payload = payload;
|
|
126
|
+
this.context = context;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// <summary>
|
|
130
|
+
/// Mints an opaque handle for a custom (non-wrapping) <see cref="IMessageBus"/>
|
|
131
|
+
/// implementer. Pack any state required to deregister into
|
|
132
|
+
/// <paramref name="externalState"/> and an id into <paramref name="externalId"/>; read
|
|
133
|
+
/// them back via <see cref="ExternalId"/> / <see cref="ExternalState"/> in your own
|
|
134
|
+
/// <see cref="IMessageBus.Deregister{T}"/>. The built-in <see cref="MessageBus"/> treats
|
|
135
|
+
/// such a handle as a no-op (it owns no store for it).
|
|
136
|
+
/// </summary>
|
|
137
|
+
public MessageBusRegistration(long externalId, object externalState)
|
|
138
|
+
: this(
|
|
139
|
+
Kind.External,
|
|
140
|
+
default,
|
|
141
|
+
0,
|
|
142
|
+
externalId,
|
|
143
|
+
0L,
|
|
144
|
+
0L,
|
|
145
|
+
null,
|
|
146
|
+
null,
|
|
147
|
+
externalState,
|
|
148
|
+
default
|
|
149
|
+
) { }
|
|
150
|
+
|
|
151
|
+
/// <summary>The invalid/empty handle. Deregistering it is a silent no-op.</summary>
|
|
152
|
+
public static readonly MessageBusRegistration None = default;
|
|
153
|
+
|
|
154
|
+
/// <summary>True when this handle represents a live registration (not <see cref="None"/>).</summary>
|
|
155
|
+
public bool IsValid => kind != Kind.None;
|
|
156
|
+
|
|
157
|
+
/// <summary>The external id supplied to <see cref="MessageBusRegistration(long, object)"/>; 0 for non-external handles.</summary>
|
|
158
|
+
public long ExternalId => kind == Kind.External ? generation : 0L;
|
|
159
|
+
|
|
160
|
+
/// <summary>The external state supplied to <see cref="MessageBusRegistration(long, object)"/>; null for non-external handles.</summary>
|
|
161
|
+
public object ExternalState => kind == Kind.External ? payload : null;
|
|
162
|
+
|
|
163
|
+
/// <inheritdoc />
|
|
164
|
+
public bool Equals(MessageBusRegistration other) =>
|
|
165
|
+
kind == other.kind
|
|
166
|
+
&& method == other.method
|
|
167
|
+
&& priority == other.priority
|
|
168
|
+
&& generation == other.generation
|
|
169
|
+
&& sweepGeneration == other.sweepGeneration
|
|
170
|
+
&& sequence == other.sequence
|
|
171
|
+
&& ReferenceEquals(capturedPrimary, other.capturedPrimary)
|
|
172
|
+
&& ReferenceEquals(capturedSecondary, other.capturedSecondary)
|
|
173
|
+
&& ReferenceEquals(payload, other.payload)
|
|
174
|
+
&& context.Equals(other.context);
|
|
175
|
+
|
|
176
|
+
/// <inheritdoc />
|
|
177
|
+
public override bool Equals(object obj) =>
|
|
178
|
+
obj is MessageBusRegistration other && Equals(other);
|
|
179
|
+
|
|
180
|
+
/// <inheritdoc />
|
|
181
|
+
public override int GetHashCode()
|
|
182
|
+
{
|
|
183
|
+
// Reference-IDENTITY hashes for the captured refs keep parity with the
|
|
184
|
+
// ReferenceEquals comparisons in Equals: RuntimeHelpers.GetHashCode is the identity
|
|
185
|
+
// hash, so it stays consistent regardless of any virtual GetHashCode override (e.g.
|
|
186
|
+
// MessageHandler hashes by owner, and delegates by target/method) and avoids the
|
|
187
|
+
// unnecessary collisions those overrides would introduce. (null -> 0.)
|
|
188
|
+
int hash = (int)kind;
|
|
189
|
+
hash = (hash * 397) ^ (int)method;
|
|
190
|
+
hash = (hash * 397) ^ priority;
|
|
191
|
+
hash = (hash * 397) ^ generation.GetHashCode();
|
|
192
|
+
hash = (hash * 397) ^ sweepGeneration.GetHashCode();
|
|
193
|
+
hash = (hash * 397) ^ sequence.GetHashCode();
|
|
194
|
+
hash = (hash * 397) ^ RuntimeHelpers.GetHashCode(capturedPrimary);
|
|
195
|
+
hash = (hash * 397) ^ RuntimeHelpers.GetHashCode(capturedSecondary);
|
|
196
|
+
hash = (hash * 397) ^ RuntimeHelpers.GetHashCode(payload);
|
|
197
|
+
hash = (hash * 397) ^ context.GetHashCode();
|
|
198
|
+
return hash;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public static bool operator ==(MessageBusRegistration left, MessageBusRegistration right) =>
|
|
202
|
+
left.Equals(right);
|
|
203
|
+
|
|
204
|
+
public static bool operator !=(MessageBusRegistration left, MessageBusRegistration right) =>
|
|
205
|
+
!left.Equals(right);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -1,9 +1,45 @@
|
|
|
1
1
|
namespace DxMessaging.Core.MessageBus
|
|
2
2
|
{
|
|
3
3
|
using System;
|
|
4
|
+
using System.Runtime.ExceptionServices;
|
|
4
5
|
using System.Threading;
|
|
5
6
|
using DxMessaging.Core;
|
|
6
7
|
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// Exception thrown when <see cref="MessageRegistrationBuildOptions.ActivateOnBuild"/> fails and
|
|
10
|
+
/// the builder cannot fully clean up the partially constructed lease before returning control.
|
|
11
|
+
/// </summary>
|
|
12
|
+
public sealed class MessageRegistrationBuildException : Exception
|
|
13
|
+
{
|
|
14
|
+
internal MessageRegistrationBuildException(
|
|
15
|
+
string message,
|
|
16
|
+
MessageRegistrationLease lease,
|
|
17
|
+
Exception activationException,
|
|
18
|
+
Exception cleanupException
|
|
19
|
+
)
|
|
20
|
+
: base(message, activationException)
|
|
21
|
+
{
|
|
22
|
+
Lease = lease ?? throw new ArgumentNullException(nameof(lease));
|
|
23
|
+
ActivationException = activationException;
|
|
24
|
+
CleanupException = cleanupException;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// <summary>
|
|
28
|
+
/// Lease that still owns retryable token cleanup. Dispose it after resolving the cleanup failure.
|
|
29
|
+
/// </summary>
|
|
30
|
+
public MessageRegistrationLease Lease { get; }
|
|
31
|
+
|
|
32
|
+
/// <summary>
|
|
33
|
+
/// Original exception raised while activating the lease.
|
|
34
|
+
/// </summary>
|
|
35
|
+
public Exception ActivationException { get; }
|
|
36
|
+
|
|
37
|
+
/// <summary>
|
|
38
|
+
/// Exception raised while attempting to clean up the partially constructed lease.
|
|
39
|
+
/// </summary>
|
|
40
|
+
public Exception CleanupException { get; }
|
|
41
|
+
}
|
|
42
|
+
|
|
7
43
|
/// <summary>
|
|
8
44
|
/// Options controlling how <see cref="MessageRegistrationBuilder"/> constructs registration tokens.
|
|
9
45
|
/// </summary>
|
|
@@ -144,6 +180,8 @@ namespace DxMessaging.Core.MessageBus
|
|
|
144
180
|
private readonly MessageRegistrationLifecycle _lifecycle;
|
|
145
181
|
private bool _isActive;
|
|
146
182
|
private bool _disposed;
|
|
183
|
+
private bool _deactivateHookInvoked;
|
|
184
|
+
private bool _disposeHookInvoked;
|
|
147
185
|
|
|
148
186
|
internal MessageRegistrationLease(
|
|
149
187
|
MessageRegistrationToken token,
|
|
@@ -159,6 +197,8 @@ namespace DxMessaging.Core.MessageBus
|
|
|
159
197
|
_lifecycle = lifecycle;
|
|
160
198
|
_isActive = false;
|
|
161
199
|
_disposed = false;
|
|
200
|
+
_deactivateHookInvoked = false;
|
|
201
|
+
_disposeHookInvoked = false;
|
|
162
202
|
}
|
|
163
203
|
|
|
164
204
|
/// <summary>
|
|
@@ -199,13 +239,27 @@ namespace DxMessaging.Core.MessageBus
|
|
|
199
239
|
}
|
|
200
240
|
|
|
201
241
|
_messageHandler.active = true;
|
|
202
|
-
|
|
203
|
-
|
|
242
|
+
_deactivateHookInvoked = false;
|
|
243
|
+
try
|
|
204
244
|
{
|
|
205
|
-
|
|
245
|
+
_token.Enable();
|
|
246
|
+
}
|
|
247
|
+
catch
|
|
248
|
+
{
|
|
249
|
+
_messageHandler.active = _token.Enabled;
|
|
250
|
+
_isActive = _token.Enabled;
|
|
251
|
+
throw;
|
|
206
252
|
}
|
|
207
253
|
|
|
254
|
+
// _isActive is set BEFORE the user callback runs so the lease's
|
|
255
|
+
// state matches the registrations even if OnActivate throws:
|
|
256
|
+
// Deactivate()/Dispose() can then always release the live
|
|
257
|
+
// registrations (a post-callback assignment left them wedged).
|
|
208
258
|
_isActive = true;
|
|
259
|
+
if (_lifecycle.OnActivate != null)
|
|
260
|
+
{
|
|
261
|
+
_lifecycle.OnActivate(_token);
|
|
262
|
+
}
|
|
209
263
|
}
|
|
210
264
|
|
|
211
265
|
/// <summary>
|
|
@@ -218,14 +272,43 @@ namespace DxMessaging.Core.MessageBus
|
|
|
218
272
|
return;
|
|
219
273
|
}
|
|
220
274
|
|
|
221
|
-
|
|
275
|
+
Exception deactivateFailure = null;
|
|
276
|
+
try
|
|
277
|
+
{
|
|
278
|
+
if (!_deactivateHookInvoked && _lifecycle.OnDeactivate != null)
|
|
279
|
+
{
|
|
280
|
+
_deactivateHookInvoked = true;
|
|
281
|
+
_lifecycle.OnDeactivate(_token);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (Exception exception)
|
|
222
285
|
{
|
|
223
|
-
|
|
286
|
+
deactivateFailure = exception;
|
|
287
|
+
}
|
|
288
|
+
finally
|
|
289
|
+
{
|
|
290
|
+
try
|
|
291
|
+
{
|
|
292
|
+
try
|
|
293
|
+
{
|
|
294
|
+
_token.Disable();
|
|
295
|
+
}
|
|
296
|
+
catch (Exception exception)
|
|
297
|
+
{
|
|
298
|
+
deactivateFailure ??= exception;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
finally
|
|
302
|
+
{
|
|
303
|
+
_messageHandler.active = _token.Enabled;
|
|
304
|
+
_isActive = _token.Enabled;
|
|
305
|
+
}
|
|
224
306
|
}
|
|
225
307
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
308
|
+
if (deactivateFailure != null)
|
|
309
|
+
{
|
|
310
|
+
ExceptionDispatchInfo.Capture(deactivateFailure).Throw();
|
|
311
|
+
}
|
|
229
312
|
}
|
|
230
313
|
|
|
231
314
|
/// <summary>
|
|
@@ -238,13 +321,58 @@ namespace DxMessaging.Core.MessageBus
|
|
|
238
321
|
return;
|
|
239
322
|
}
|
|
240
323
|
|
|
241
|
-
|
|
242
|
-
|
|
324
|
+
Exception disposeFailure = null;
|
|
325
|
+
bool tokenCleanupFailed = false;
|
|
326
|
+
try
|
|
327
|
+
{
|
|
328
|
+
try
|
|
329
|
+
{
|
|
330
|
+
Deactivate();
|
|
331
|
+
}
|
|
332
|
+
catch (Exception exception)
|
|
333
|
+
{
|
|
334
|
+
disposeFailure = exception;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!_disposeHookInvoked && _lifecycle.OnDispose != null)
|
|
338
|
+
{
|
|
339
|
+
_disposeHookInvoked = true;
|
|
340
|
+
try
|
|
341
|
+
{
|
|
342
|
+
_lifecycle.OnDispose(_token);
|
|
343
|
+
}
|
|
344
|
+
catch (Exception exception)
|
|
345
|
+
{
|
|
346
|
+
disposeFailure ??= exception;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
finally
|
|
243
351
|
{
|
|
244
|
-
|
|
352
|
+
try
|
|
353
|
+
{
|
|
354
|
+
try
|
|
355
|
+
{
|
|
356
|
+
_token.Dispose();
|
|
357
|
+
}
|
|
358
|
+
catch (Exception exception)
|
|
359
|
+
{
|
|
360
|
+
tokenCleanupFailed = true;
|
|
361
|
+
disposeFailure ??= exception;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
finally
|
|
365
|
+
{
|
|
366
|
+
_messageHandler.active = _token.Enabled;
|
|
367
|
+
_isActive = _token.Enabled;
|
|
368
|
+
_disposed = !tokenCleanupFailed;
|
|
369
|
+
}
|
|
245
370
|
}
|
|
246
371
|
|
|
247
|
-
|
|
372
|
+
if (disposeFailure != null)
|
|
373
|
+
{
|
|
374
|
+
ExceptionDispatchInfo.Capture(disposeFailure).Throw();
|
|
375
|
+
}
|
|
248
376
|
}
|
|
249
377
|
|
|
250
378
|
internal void InvokeBuildHook()
|
|
@@ -305,6 +433,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
305
433
|
/// <param name="options">Options controlling bus selection, diagnostics, and lifecycle behavior.</param>
|
|
306
434
|
/// <returns>A lease that wraps the created <see cref="MessageRegistrationToken"/>.</returns>
|
|
307
435
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="options"/> is <see langword="null"/>.</exception>
|
|
436
|
+
/// <exception cref="MessageRegistrationBuildException">Thrown when ActivateOnBuild activation fails and automatic cleanup remains retryable.</exception>
|
|
308
437
|
public MessageRegistrationLease Build(MessageRegistrationBuildOptions options)
|
|
309
438
|
{
|
|
310
439
|
if (options == null)
|
|
@@ -338,12 +467,56 @@ namespace DxMessaging.Core.MessageBus
|
|
|
338
467
|
|
|
339
468
|
if (options.ActivateOnBuild)
|
|
340
469
|
{
|
|
341
|
-
|
|
470
|
+
try
|
|
471
|
+
{
|
|
472
|
+
lease.Activate();
|
|
473
|
+
}
|
|
474
|
+
catch (Exception exception)
|
|
475
|
+
{
|
|
476
|
+
HandleActivateOnBuildFailure(lease, exception);
|
|
477
|
+
}
|
|
342
478
|
}
|
|
343
479
|
|
|
344
480
|
return lease;
|
|
345
481
|
}
|
|
346
482
|
|
|
483
|
+
private static void HandleActivateOnBuildFailure(
|
|
484
|
+
MessageRegistrationLease lease,
|
|
485
|
+
Exception activationException
|
|
486
|
+
)
|
|
487
|
+
{
|
|
488
|
+
Exception cleanupException = null;
|
|
489
|
+
try
|
|
490
|
+
{
|
|
491
|
+
lease.Dispose();
|
|
492
|
+
}
|
|
493
|
+
catch (Exception exception)
|
|
494
|
+
{
|
|
495
|
+
cleanupException = exception;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (lease.Token.Enabled)
|
|
499
|
+
{
|
|
500
|
+
throw new MessageRegistrationBuildException(
|
|
501
|
+
"ActivateOnBuild failed and automatic lease cleanup did not complete. Dispose the Lease property after resolving the cleanup failure.",
|
|
502
|
+
lease,
|
|
503
|
+
activationException,
|
|
504
|
+
cleanupException
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (cleanupException != null && MessagingDebug.enabled)
|
|
509
|
+
{
|
|
510
|
+
MessagingDebug.Log(
|
|
511
|
+
LogLevel.Error,
|
|
512
|
+
"ActivateOnBuild cleanup failed after activation failure: {0}",
|
|
513
|
+
cleanupException
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
ExceptionDispatchInfo.Capture(activationException).Throw();
|
|
518
|
+
}
|
|
519
|
+
|
|
347
520
|
private static InstanceId ResolveOwner(MessageRegistrationBuildOptions options)
|
|
348
521
|
{
|
|
349
522
|
#if UNITY_2021_3_OR_NEWER
|
|
@@ -359,7 +532,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
359
532
|
return component;
|
|
360
533
|
}
|
|
361
534
|
|
|
362
|
-
return new InstanceId(options.UnityOwner
|
|
535
|
+
return new InstanceId(InstanceId.StableId(options.UnityOwner));
|
|
363
536
|
}
|
|
364
537
|
#endif
|
|
365
538
|
if (options.Owner.HasValue)
|