Auto status change to "Under Review"
| @@ -0,0 +1,9 | |||||
|
|
1 | namespace Implab { | |||
|
|
2 | public enum PromiseState { | |||
|
|
3 | Pending, | |||
|
|
4 | ||||
|
|
5 | Resolved, | |||
|
|
6 | ||||
|
|
7 | Rejected | |||
|
|
8 | } | |||
|
|
9 | } No newline at end of file | |||
| @@ -5,28 +5,61 using System.Reflection; | |||||
| 5 | using System.Diagnostics; |
|
5 | using System.Diagnostics; | |
| 6 |
|
6 | |||
| 7 | namespace Implab { |
|
7 | namespace Implab { | |
|
|
8 | /// <summary> | |||
|
|
9 | /// Abstract class for creation of custom one-shot thread safe events. | |||
|
|
10 | /// </summary> | |||
|
|
11 | /// <remarks> | |||
|
|
12 | /// <para> | |||
|
|
13 | /// An event is something that should happen in the future and the | |||
|
|
14 | /// triggering of the event causes execution of some pending actions | |||
|
|
15 | /// which are formely event handlers. One-shot events occur only once | |||
|
|
16 | /// and any handler added after the event is triggered should run | |||
|
|
17 | /// without a delay. | |||
|
|
18 | /// </para> | |||
|
|
19 | /// <para> | |||
|
|
20 | /// The lifecycle of the one-shot event is tipically consists of following | |||
|
|
21 | /// phases. | |||
|
|
22 | /// <list> | |||
|
|
23 | /// <description>Pending state. This is the initial state of the event. Any | |||
|
|
24 | /// handler added to the event will be queued for the future execution. | |||
|
|
25 | /// </description> | |||
|
|
26 | /// <description>Transitional state. This is intermediate state between pending | |||
|
|
27 | /// and fulfilled states, during this state internal initialization and storing | |||
|
|
28 | /// of the result occurs. | |||
|
|
29 | /// </description> | |||
|
|
30 | /// <description>Fulfilled state. The event contains the result, all queued | |||
|
|
31 | /// handlers are signalled to run and newly added handlers are executed | |||
|
|
32 | /// immediatelly. | |||
|
|
33 | /// </description> | |||
|
|
34 | /// </list> | |||
|
|
35 | /// </para> | |||
|
|
36 | /// </remarks> | |||
| 8 | public abstract class AbstractEvent<THandler> where THandler : class { |
|
37 | public abstract class AbstractEvent<THandler> where THandler : class { | |
| 9 |
|
||||
| 10 | const int PENDING_SATE = 0; |
|
38 | const int PENDING_SATE = 0; | |
| 11 | protected const int TRANSITIONAL_STATE = 1; |
|
|||
| 12 |
|
39 | |||
| 13 |
|
|
40 | const int TRANSITIONAL_STATE = 1; | |
| 14 | protected const int REJECTED_STATE = 3; |
|
41 | ||
|
|
42 | const int FULFILLED_STATE = 2; | |||
| 15 |
|
43 | |||
| 16 | volatile int m_state; |
|
44 | volatile int m_state; | |
| 17 | Exception m_error; |
|
|||
| 18 |
|
45 | |||
| 19 | THandler m_handler; |
|
46 | THandler m_handler; | |
| 20 | SimpleAsyncQueue<THandler> m_extraHandlers; |
|
47 | SimpleAsyncQueue<THandler> m_extraHandlers; | |
| 21 |
|
48 | |||
|
|
49 | public bool IsFulfilled { | |||
|
|
50 | get { | |||
|
|
51 | return m_state > TRANSITIONAL_STATE; | |||
|
|
52 | } | |||
|
|
53 | } | |||
|
|
54 | ||||
| 22 | #region state managment |
|
55 | #region state managment | |
| 23 | protected bool BeginTransit() { |
|
56 | protected bool BeginTransit() { | |
| 24 | return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE); |
|
57 | return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE); | |
| 25 | } |
|
58 | } | |
| 26 |
|
59 | |||
| 27 |
protected void CompleteTransit( |
|
60 | protected void CompleteTransit() { | |
| 28 | #if DEBUG |
|
61 | #if DEBUG | |
| 29 |
if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, |
|
62 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, FULFILLED_STATE, TRANSITIONAL_STATE)) | |
| 30 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); |
|
63 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
| 31 | #else |
|
64 | #else | |
| 32 | m_state = state; |
|
65 | m_state = state; | |
| @@ -43,47 +76,13 namespace Implab { | |||||
| 43 | } |
|
76 | } | |
| 44 | } |
|
77 | } | |
| 45 |
|
78 | |||
| 46 | protected bool BeginSetResult() { |
|
|||
| 47 | if (!BeginTransit()) { |
|
|||
| 48 | WaitTransition(); |
|
|||
| 49 | return false; |
|
|||
| 50 | } |
|
|||
| 51 | return true; |
|
|||
| 52 | } |
|
|||
| 53 |
|
79 | |||
| 54 | protected void EndSetResult() { |
|
80 | protected abstract void SignalHandler(THandler handler); | |
| 55 | CompleteTransit(SUCCEEDED_STATE); |
|
|||
| 56 | } |
|
|||
| 57 |
|
||||
| 58 |
|
||||
| 59 |
|
||||
| 60 | /// <summary> |
|
|||
| 61 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ |
|
|||
| 62 | /// </summary> |
|
|||
| 63 | /// <remarks> |
|
|||
| 64 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² |
|
|||
| 65 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ |
|
|||
| 66 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. |
|
|||
| 67 | /// </remarks> |
|
|||
| 68 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> |
|
|||
| 69 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> |
|
|||
| 70 | protected void SetError(Exception error) { |
|
|||
| 71 | if (BeginTransit()) { |
|
|||
| 72 | m_error = error; |
|
|||
| 73 | CompleteTransit(REJECTED_STATE); |
|
|||
| 74 | } else { |
|
|||
| 75 | WaitTransition(); |
|
|||
| 76 | if (m_state == SUCCEEDED_STATE) |
|
|||
| 77 | throw new InvalidOperationException("The promise is already resolved"); |
|
|||
| 78 | } |
|
|||
| 79 | } |
|
|||
| 80 |
|
||||
| 81 | protected abstract void SignalHandler(THandler handler, int signal); |
|
|||
| 82 |
|
81 | |||
| 83 | void Signal() { |
|
82 | void Signal() { | |
| 84 | THandler handler; |
|
83 | THandler handler; | |
| 85 | while (TryDequeueHandler(out handler)) |
|
84 | while (TryDequeueHandler(out handler)) | |
| 86 |
SignalHandler(handler |
|
85 | SignalHandler(handler); | |
| 87 | } |
|
86 | } | |
| 88 |
|
87 | |||
| 89 | #endregion |
|
88 | #endregion | |
| @@ -94,46 +93,41 namespace Implab { | |||||
| 94 | protected void WaitResult(int timeout) { |
|
93 | protected void WaitResult(int timeout) { | |
| 95 | if (!(IsFulfilled || GetFulfillSignal().Wait(timeout))) |
|
94 | if (!(IsFulfilled || GetFulfillSignal().Wait(timeout))) | |
| 96 | throw new TimeoutException(); |
|
95 | throw new TimeoutException(); | |
| 97 |
|
||||
| 98 | if (IsRejected) |
|
|||
| 99 | Rethrow(); |
|
|||
| 100 | } |
|
96 | } | |
| 101 |
|
97 | |||
| 102 | protected void Rethrow() { |
|
98 | ||
| 103 | Debug.Assert(m_error != null); |
|
|||
| 104 | if (m_error is OperationCanceledException) |
|
|||
| 105 | throw new OperationCanceledException("Operation cancelled", m_error); |
|
|||
| 106 | else |
|
|||
| 107 | throw new TargetInvocationException(m_error); |
|
|||
| 108 | } |
|
|||
| 109 | #endregion |
|
99 | #endregion | |
| 110 |
|
100 | |||
| 111 | #region handlers managment |
|
101 | #region handlers managment | |
| 112 |
|
102 | |||
| 113 | protected void AddHandler(THandler handler) { |
|
103 | protected void AddHandler(THandler handler) { | |
| 114 |
|
104 | |||
| 115 |
if ( |
|
105 | if (IsFulfilled) { | |
| 116 | // the promise is in the resolved state, just invoke the handler |
|
106 | // the promise is in the resolved state, just invoke the handler | |
| 117 |
SignalHandler(handler |
|
107 | SignalHandler(handler); | |
| 118 | } else { |
|
108 | } else { | |
| 119 | if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { |
|
109 | EnqueueHandler(handler); | |
| 120 | if (m_extraHandlers == null) |
|
|||
| 121 | // compare-exchange will fprotect from loosing already created queue |
|
|||
| 122 | Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null); |
|
|||
| 123 | m_extraHandlers.Enqueue(handler); |
|
|||
| 124 | } |
|
|||
| 125 |
|
110 | |||
| 126 |
if ( |
|
111 | if (IsFulfilled && TryDequeueHandler(out handler)) | |
| 127 | // if the promise have been resolved while we was adding the handler to the queue |
|
112 | // if the promise have been resolved while we was adding the handler to the queue | |
| 128 | // we can't guarantee that someone is still processing it |
|
113 | // we can't guarantee that someone is still processing it | |
| 129 | // therefore we need to fetch a handler from the queue and execute it |
|
114 | // therefore we need to fetch a handler from the queue and execute it | |
| 130 | // note that fetched handler may be not the one that we have added |
|
115 | // note that fetched handler may be not the one that we have added | |
| 131 | // even we can fetch no handlers at all :) |
|
116 | // even we can fetch no handlers at all :) | |
| 132 |
SignalHandler(handler |
|
117 | SignalHandler(handler); | |
| 133 | } |
|
118 | } | |
| 134 |
|
119 | |||
| 135 | } |
|
120 | } | |
| 136 |
|
121 | |||
|
|
122 | void EnqueueHandler(THandler handler) { | |||
|
|
123 | if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { | |||
|
|
124 | if (m_extraHandlers == null) | |||
|
|
125 | // compare-exchange will protect from loosing already created queue | |||
|
|
126 | Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null); | |||
|
|
127 | m_extraHandlers.Enqueue(handler); | |||
|
|
128 | } | |||
|
|
129 | } | |||
|
|
130 | ||||
| 137 | bool TryDequeueHandler(out THandler handler) { |
|
131 | bool TryDequeueHandler(out THandler handler) { | |
| 138 | handler = Interlocked.Exchange(ref m_handler, null); |
|
132 | handler = Interlocked.Exchange(ref m_handler, null); | |
| 139 | if (handler != null) |
|
133 | if (handler != null) | |
| @@ -142,29 +136,6 namespace Implab { | |||||
| 142 | } |
|
136 | } | |
| 143 |
|
137 | |||
| 144 | #endregion |
|
138 | #endregion | |
| 145 |
|
||||
| 146 | #region IPromise implementation |
|
|||
| 147 |
|
||||
| 148 | public bool IsFulfilled { |
|
|||
| 149 | get { |
|
|||
| 150 | return m_state > TRANSITIONAL_STATE; |
|
|||
| 151 | } |
|
|||
| 152 | } |
|
|||
| 153 |
|
||||
| 154 | public bool IsRejected { |
|
|||
| 155 | get { |
|
|||
| 156 | return m_state == REJECTED_STATE; |
|
|||
| 157 | } |
|
|||
| 158 | } |
|
|||
| 159 |
|
||||
| 160 | #endregion |
|
|||
| 161 |
|
||||
| 162 | public Exception RejectReason { |
|
|||
| 163 | get { |
|
|||
| 164 | return m_error; |
|
|||
| 165 | } |
|
|||
| 166 | } |
|
|||
| 167 |
|
||||
| 168 | } |
|
139 | } | |
| 169 | } |
|
140 | } | |
| 170 |
|
141 | |||
| @@ -1,50 +1,77 | |||||
| 1 | using System; |
|
1 | using System; | |
|
|
2 | using System.Diagnostics; | |||
|
|
3 | using System.Reflection; | |||
| 2 | using Implab.Parallels; |
|
4 | using Implab.Parallels; | |
| 3 |
|
5 | |||
| 4 | namespace Implab { |
|
6 | namespace Implab { | |
| 5 | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { |
|
7 | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | |
| 6 | public class HandlerDescriptor { |
|
8 | public class HandlerDescriptor { | |
| 7 |
readonly Action m_ |
|
9 | readonly Action m_resolve; | |
| 8 |
readonly Action<Exception> m_ |
|
10 | readonly Action<Exception> m_reject; | |
|
|
11 | ||||
|
|
12 | readonly IDeferred m_deferred; | |||
| 9 | public HandlerDescriptor(Action success, Action<Exception> error) { |
|
13 | public HandlerDescriptor(Action success, Action<Exception> error) { | |
| 10 |
m_ |
|
14 | m_resolve = success; | |
| 11 |
m_ |
|
15 | m_reject = error; | |
| 12 | } |
|
16 | } | |
| 13 |
|
17 | |||
| 14 | public void SignalSuccess() { |
|
18 | public void SignalSuccess() { | |
| 15 |
|
|
19 | try { | |
| 16 |
|
|
20 | if (m_resolve != null) | |
| 17 |
m_ |
|
21 | m_resolve(); | |
| 18 | // Analysis disable once EmptyGeneralCatchClause |
|
22 | m_deferred.Resolve(); | |
| 19 |
|
|
23 | } catch (Exception ex) { | |
| 20 |
|
|
24 | m_deferred.Reject(ex); | |
| 21 | } |
|
25 | } | |
| 22 | } |
|
26 | } | |
| 23 |
|
27 | |||
| 24 | public void SignalError(Exception err) { |
|
28 | public void SignalError(Exception err) { | |
| 25 |
if (m_ |
|
29 | if (m_reject != null) { | |
| 26 | try { |
|
30 | try { | |
| 27 |
m_ |
|
31 | m_reject(err); | |
| 28 | // Analysis disable once EmptyGeneralCatchClause |
|
32 | m_deferred.Resolve(); | |
| 29 | } catch { |
|
33 | } catch (Exception ex) { | |
|
|
34 | m_deferred.Reject(ex); | |||
| 30 | } |
|
35 | } | |
| 31 | } |
|
36 | } | |
| 32 | } |
|
37 | } | |
| 33 | } |
|
38 | } | |
| 34 |
|
39 | |||
|
|
40 | PromiseState m_state; | |||
|
|
41 | ||||
|
|
42 | Exception m_error; | |||
|
|
43 | ||||
|
|
44 | public bool IsRejected { | |||
|
|
45 | get { | |||
|
|
46 | return m_state == PromiseState.Rejected; | |||
|
|
47 | } | |||
|
|
48 | } | |||
|
|
49 | ||||
|
|
50 | public bool IsResolved { | |||
|
|
51 | get { | |||
|
|
52 | return m_state == PromiseState.Resolved; | |||
|
|
53 | } | |||
|
|
54 | } | |||
|
|
55 | ||||
|
|
56 | public Exception RejectReason { | |||
|
|
57 | get { | |||
|
|
58 | return m_error; | |||
|
|
59 | } | |||
|
|
60 | } | |||
|
|
61 | ||||
| 35 |
|
62 | |||
| 36 | #region implemented abstract members of AbstractPromise |
|
63 | #region implemented abstract members of AbstractPromise | |
| 37 |
|
64 | |||
| 38 |
protected override void SignalHandler(HandlerDescriptor handler |
|
65 | protected override void SignalHandler(HandlerDescriptor handler) { | |
| 39 |
switch ( |
|
66 | switch (m_state) { | |
| 40 | case SUCCEEDED_STATE: |
|
67 | case PromiseState.Resolved: | |
| 41 | handler.SignalSuccess(); |
|
68 | handler.SignalSuccess(); | |
| 42 | break; |
|
69 | break; | |
| 43 | case REJECTED_STATE: |
|
70 | case PromiseState.Rejected: | |
| 44 | handler.SignalError(RejectReason); |
|
71 | handler.SignalError(RejectReason); | |
| 45 | break; |
|
72 | break; | |
| 46 | default: |
|
73 | default: | |
| 47 |
throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", |
|
74 | throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | |
| 48 | } |
|
75 | } | |
| 49 | } |
|
76 | } | |
| 50 |
|
77 | |||
| @@ -56,12 +83,47 namespace Implab { | |||||
| 56 |
|
83 | |||
| 57 | #endregion |
|
84 | #endregion | |
| 58 |
|
85 | |||
|
|
86 | protected void CompleteResolve() { | |||
|
|
87 | m_state = PromiseState.Resolved; | |||
|
|
88 | CompleteTransit(); | |||
|
|
89 | } | |||
|
|
90 | ||||
| 59 | public Type ResultType { |
|
91 | public Type ResultType { | |
| 60 | get { |
|
92 | get { | |
| 61 | return typeof(void); |
|
93 | return typeof(void); | |
| 62 | } |
|
94 | } | |
| 63 | } |
|
95 | } | |
| 64 |
|
96 | |||
|
|
97 | /// <summary> | |||
|
|
98 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ | |||
|
|
99 | /// </summary> | |||
|
|
100 | /// <remarks> | |||
|
|
101 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² | |||
|
|
102 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ | |||
|
|
103 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. | |||
|
|
104 | /// </remarks> | |||
|
|
105 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> | |||
|
|
106 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> | |||
|
|
107 | protected void SetError(Exception error) { | |||
|
|
108 | if (BeginTransit()) { | |||
|
|
109 | m_error = error; | |||
|
|
110 | m_state = PromiseState.Rejected; | |||
|
|
111 | CompleteTransit(); | |||
|
|
112 | } else { | |||
|
|
113 | WaitTransition(); | |||
|
|
114 | if (m_state == PromiseState.Resolved) | |||
|
|
115 | throw new InvalidOperationException("The promise is already resolved"); | |||
|
|
116 | } | |||
|
|
117 | } | |||
|
|
118 | ||||
|
|
119 | protected void Rethrow() { | |||
|
|
120 | Debug.Assert(m_error != null); | |||
|
|
121 | if (m_error is OperationCanceledException) | |||
|
|
122 | throw new OperationCanceledException("Operation cancelled", m_error); | |||
|
|
123 | else | |||
|
|
124 | throw new TargetInvocationException(m_error); | |||
|
|
125 | } | |||
|
|
126 | ||||
| 65 | public void On(Action success, Action<Exception> error) { |
|
127 | public void On(Action success, Action<Exception> error) { | |
| 66 | AddHandler(new HandlerDescriptor(success, error)); |
|
128 | AddHandler(new HandlerDescriptor(success, error)); | |
| 67 | } |
|
129 | } | |
| @@ -72,16 +134,13 namespace Implab { | |||||
| 72 |
|
134 | |||
| 73 | public void Join() { |
|
135 | public void Join() { | |
| 74 | WaitResult(-1); |
|
136 | WaitResult(-1); | |
|
|
137 | if (IsRejected) | |||
|
|
138 | Rethrow(); | |||
| 75 | } |
|
139 | } | |
| 76 |
|
140 | |||
| 77 | public void Join(int timeout) { |
|
141 | public void Join(int timeout) { | |
| 78 | WaitResult(timeout); |
|
142 | WaitResult(timeout); | |
| 79 | } |
|
143 | } | |
| 80 |
|
||||
| 81 | protected void SetResult() { |
|
|||
| 82 | if(BeginSetResult()) |
|
|||
| 83 | EndSetResult(); |
|
|||
| 84 | } |
|
|||
| 85 | } |
|
144 | } | |
| 86 | } |
|
145 | } | |
| 87 |
|
146 | |||
| @@ -4,7 +4,7 using System.Linq; | |||||
| 4 | using System.Text; |
|
4 | using System.Text; | |
| 5 |
|
5 | |||
| 6 | namespace Implab { |
|
6 | namespace Implab { | |
| 7 |
public interface IPromise |
|
7 | public interface IPromise { | |
| 8 |
|
8 | |||
| 9 | /// <summary> |
|
9 | /// <summary> | |
| 10 | /// Π’ΠΈΠΏ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌΠΎΠ³ΠΎ ΡΠ΅ΡΠ΅Π· Π΄Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅. |
|
10 | /// Π’ΠΈΠΏ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌΠΎΠ³ΠΎ ΡΠ΅ΡΠ΅Π· Π΄Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅. | |
| @@ -2,24 +2,24 | |||||
| 2 | using Implab.Parallels; |
|
2 | using Implab.Parallels; | |
| 3 |
|
3 | |||
| 4 | namespace Implab { |
|
4 | namespace Implab { | |
| 5 |
public class Promise : AbstractPromise |
|
5 | public class Promise : AbstractPromise { | |
| 6 | public static readonly IPromise Success; |
|
6 | public static readonly IPromise Success; | |
| 7 |
|
7 | |||
| 8 | static Promise() { |
|
8 | static Promise() { | |
| 9 | Success = new SuccessPromise(); |
|
9 | Success = new SuccessPromise(); | |
| 10 | } |
|
10 | } | |
| 11 |
|
11 | |||
| 12 |
|
|
12 | internal void ResolvePromise() { | |
| 13 | SetResult(); |
|
13 | SetResult(); | |
| 14 | } |
|
14 | } | |
| 15 |
|
15 | |||
| 16 |
|
|
16 | internal void RejectPromise(Exception error) { | |
| 17 | SetError(error); |
|
17 | SetError(error); | |
| 18 | } |
|
18 | } | |
| 19 |
|
19 | |||
| 20 |
public static IPromise |
|
20 | public static IPromise Reject(Exception exception) { | |
| 21 | return new FailedPromise(exception); |
|
21 | return new FailedPromise(exception); | |
| 22 | } |
|
22 | } | |
| 23 | } |
|
23 | } | |
| 24 | } |
|
24 | } | |
| 25 |
|
25 | |||
General Comments 3
ok, latest stable version should be in default
You need to be logged in to leave comments.
Login now
