A game about forced loneliness, made by TACStudios
1using System;
2using Unity.Profiling;
3
4namespace UnityEngine.InputSystem.Utilities
5{
6 internal static class DelegateHelpers
7 {
8 // InvokeCallbacksSafe protects both against the callback getting removed while being called
9 // and against exceptions being thrown by the callback.
10
11 public static void InvokeCallbacksSafe(ref CallbackArray<Action> callbacks, ProfilerMarker marker, string callbackName, object context = null)
12 {
13 if (callbacks.length == 0)
14 return;
15 marker.Begin();
16 callbacks.LockForChanges();
17 for (var i = 0; i < callbacks.length; ++i)
18 {
19 try
20 {
21 callbacks[i]();
22 }
23 catch (Exception exception)
24 {
25 Debug.LogException(exception);
26 if (context != null)
27 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
28 else
29 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
30 }
31 }
32 callbacks.UnlockForChanges();
33 marker.End();
34 }
35
36 public static void InvokeCallbacksSafe<TValue>(ref CallbackArray<Action<TValue>> callbacks, TValue argument, string callbackName, object context = null)
37 {
38 if (callbacks.length == 0)
39 return;
40 Profiling.Profiler.BeginSample(callbackName);
41 callbacks.LockForChanges();
42 for (var i = 0; i < callbacks.length; ++i)
43 {
44 try
45 {
46 callbacks[i](argument);
47 }
48 catch (Exception exception)
49 {
50 Debug.LogException(exception);
51 if (context != null)
52 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
53 else
54 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
55 }
56 }
57 callbacks.UnlockForChanges();
58 Profiling.Profiler.EndSample();
59 }
60
61 public static void InvokeCallbacksSafe<TValue1, TValue2>(ref CallbackArray<Action<TValue1, TValue2>> callbacks, TValue1 argument1, TValue2 argument2, ProfilerMarker marker, string callbackName, object context = null)
62 {
63 if (callbacks.length == 0)
64 return;
65 marker.Begin();
66 callbacks.LockForChanges();
67 for (var i = 0; i < callbacks.length; ++i)
68 {
69 try
70 {
71 callbacks[i](argument1, argument2);
72 }
73 catch (Exception exception)
74 {
75 Debug.LogException(exception);
76 if (context != null)
77 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
78 else
79 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
80 }
81 }
82 callbacks.UnlockForChanges();
83 marker.End();
84 }
85
86 public static bool InvokeCallbacksSafe_AnyCallbackReturnsTrue<TValue1, TValue2>(ref CallbackArray<Func<TValue1, TValue2, bool>> callbacks,
87 TValue1 argument1, TValue2 argument2, string callbackName, object context = null)
88 {
89 if (callbacks.length == 0)
90 return true;
91 Profiling.Profiler.BeginSample(callbackName);
92 callbacks.LockForChanges();
93 for (var i = 0; i < callbacks.length; ++i)
94 {
95 try
96 {
97 if (callbacks[i](argument1, argument2))
98 {
99 callbacks.UnlockForChanges();
100 Profiling.Profiler.EndSample();
101 return true;
102 }
103 }
104 catch (Exception exception)
105 {
106 Debug.LogException(exception);
107 if (context != null)
108 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
109 else
110 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
111 }
112 }
113 callbacks.UnlockForChanges();
114 Profiling.Profiler.EndSample();
115 return false;
116 }
117
118 /// <summary>
119 /// Invokes the given callbacks and also invokes any callback returned from the result of the first.
120 /// </summary>
121 /// <seealso cref="System.Action"/>
122 /// <remarks>
123 /// Allows an chaining up an additional, optional block of code to the original callback
124 /// and allow the external code make the decision about whether this code should be executed.
125 /// </remarks>
126 public static void InvokeCallbacksSafe_AndInvokeReturnedActions<TValue>(
127 ref CallbackArray<Func<TValue, Action>> callbacks, TValue argument,
128 string callbackName, object context = null)
129 {
130 if (callbacks.length == 0)
131 return;
132
133 Profiling.Profiler.BeginSample(callbackName);
134 callbacks.LockForChanges();
135 for (var i = 0; i < callbacks.length; ++i)
136 {
137 try
138 {
139 callbacks[i](argument)?.Invoke();
140 }
141 catch (Exception exception)
142 {
143 Debug.LogException(exception);
144 if (context != null)
145 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
146 else
147 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
148 }
149 }
150 callbacks.UnlockForChanges();
151 Profiling.Profiler.EndSample();
152 }
153
154 /// <summary>
155 /// Invokes the given callbacks and returns true if any of them returned a non-null result.
156 /// </summary>
157 /// <remarks>
158 /// Returns false if every callback invocation returned null.
159 /// </remarks>
160 public static bool InvokeCallbacksSafe_AnyCallbackReturnsObject<TValue, TReturn>(
161 ref CallbackArray<Func<TValue, TReturn>> callbacks, TValue argument,
162 string callbackName, object context = null)
163 {
164 if (callbacks.length == 0)
165 return false;
166
167 Profiling.Profiler.BeginSample(callbackName);
168 callbacks.LockForChanges();
169 for (var i = 0; i < callbacks.length; ++i)
170 {
171 try
172 {
173 var ret = callbacks[i](argument);
174 if (ret != null)
175 {
176 callbacks.UnlockForChanges();
177 Profiling.Profiler.EndSample();
178 return true;
179 }
180 }
181 catch (Exception exception)
182 {
183 Debug.LogException(exception);
184 if (context != null)
185 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
186 else
187 Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
188 }
189 }
190 callbacks.UnlockForChanges();
191 Profiling.Profiler.EndSample();
192 return false;
193 }
194 }
195}