File size: 7,919 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
using System;
using UnityEngine.Profiling;

namespace UnityEngine.InputSystem.Utilities
{
    internal static class DelegateHelpers
    {
        // InvokeCallbacksSafe protects both against the callback getting removed while being called
        // and against exceptions being thrown by the callback.

        public static void InvokeCallbacksSafe(ref CallbackArray<Action> callbacks, string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return;
            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    callbacks[i]();
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
        }

        public static void InvokeCallbacksSafe<TValue>(ref CallbackArray<Action<TValue>> callbacks, TValue argument, string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return;
            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    callbacks[i](argument);
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
        }

        public static void InvokeCallbacksSafe<TValue1, TValue2>(ref CallbackArray<Action<TValue1, TValue2>> callbacks, TValue1 argument1, TValue2 argument2, string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return;
            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    callbacks[i](argument1, argument2);
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
        }

        public static bool InvokeCallbacksSafe_AnyCallbackReturnsTrue<TValue1, TValue2>(ref CallbackArray<Func<TValue1, TValue2, bool>> callbacks,
            TValue1 argument1, TValue2 argument2, string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return true;
            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    if (callbacks[i](argument1, argument2))
                    {
                        callbacks.UnlockForChanges();
                        Profiler.EndSample();
                        return true;
                    }
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
            return false;
        }

        /// <summary>
        /// Invokes the given callbacks and also invokes any callback returned from the result of the first.
        /// </summary>
        /// <seealso cref="System.Action"/>
        /// <remarks>
        /// Allows an chaining up an additional, optional block of code to the original callback
        /// and allow the external code make the decision about whether this code should be executed.
        /// </remarks>
        public static void InvokeCallbacksSafe_AndInvokeReturnedActions<TValue>(
            ref CallbackArray<Func<TValue, Action>> callbacks, TValue argument,
            string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return;

            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    callbacks[i](argument)?.Invoke();
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
        }

        /// <summary>
        /// Invokes the given callbacks and returns true if any of them returned a non-null result.
        /// </summary>
        /// <remarks>
        /// Returns false if every callback invocation returned null.
        /// </remarks>
        public static bool InvokeCallbacksSafe_AnyCallbackReturnsObject<TValue, TReturn>(
            ref CallbackArray<Func<TValue, TReturn>> callbacks, TValue argument,
            string callbackName, object context = null)
        {
            if (callbacks.length == 0)
                return false;

            Profiler.BeginSample(callbackName);
            callbacks.LockForChanges();
            for (var i = 0; i < callbacks.length; ++i)
            {
                try
                {
                    var ret = callbacks[i](argument);
                    if (ret != null)
                    {
                        callbacks.UnlockForChanges();
                        Profiler.EndSample();
                        return true;
                    }
                }
                catch (Exception exception)
                {
                    Debug.LogException(exception);
                    if (context != null)
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
                    else
                        Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
                }
            }
            callbacks.UnlockForChanges();
            Profiler.EndSample();
            return false;
        }
    }
}