Mercurial > pub > ImplabNet
comparison Implab/AbstractPromise.cs @ 244:eee3e49dd1ff v3
working on promises
author | cin |
---|---|
date | Thu, 25 Jan 2018 19:09:16 +0300 |
parents | b1e0ffdf3451 |
children | fb70574741a1 |
comparison
equal
deleted
inserted
replaced
243:b1e0ffdf3451 | 244:eee3e49dd1ff |
---|---|
2 using System.Diagnostics; | 2 using System.Diagnostics; |
3 using System.Reflection; | 3 using System.Reflection; |
4 using Implab.Parallels; | 4 using Implab.Parallels; |
5 | 5 |
6 namespace Implab { | 6 namespace Implab { |
7 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | 7 public class AbstractPromise : AbstractEvent<IResolvable>, IPromise { |
8 public class HandlerDescriptor { | |
9 readonly Action m_resolve; | |
10 readonly Action<Exception> m_reject; | |
11 | 8 |
12 readonly IDeferred m_deferred; | 9 class ResolvableSignal : IResolvable { |
13 public HandlerDescriptor(Action success, Action<Exception> error) { | 10 public Signal Signal { get; private set; } |
14 m_resolve = success; | 11 public ResolvableSignal() { |
15 m_reject = error; | 12 Signal = new Signal(); |
16 } | 13 } |
17 | 14 |
18 public void SignalSuccess() { | 15 |
19 try { | 16 public void Reject(Exception error) { |
20 if (m_resolve != null) | 17 Signal.Set(); |
21 m_resolve(); | |
22 m_deferred.Resolve(); | |
23 } catch (Exception ex) { | |
24 m_deferred.Reject(ex); | |
25 } | |
26 } | 18 } |
27 | 19 |
28 public void SignalError(Exception err) { | 20 public void Resolve() { |
29 if (m_reject != null) { | 21 Signal.Set(); |
30 try { | |
31 m_reject(err); | |
32 m_deferred.Resolve(); | |
33 } catch (Exception ex) { | |
34 m_deferred.Reject(ex); | |
35 } | |
36 } | |
37 } | 22 } |
38 } | 23 } |
39 | 24 |
40 PromiseState m_state; | 25 PromiseState m_state; |
41 | 26 |
45 get { | 30 get { |
46 return m_state == PromiseState.Rejected; | 31 return m_state == PromiseState.Rejected; |
47 } | 32 } |
48 } | 33 } |
49 | 34 |
50 public bool IsResolved { | 35 public bool IsFulfilled { |
51 get { | 36 get { |
52 return m_state == PromiseState.Resolved; | 37 return m_state == PromiseState.Fulfilled; |
53 } | 38 } |
54 } | 39 } |
55 | 40 |
56 public Exception RejectReason { | 41 public Exception RejectReason { |
57 get { | 42 get { |
58 return m_error; | 43 return m_error; |
59 } | 44 } |
60 } | 45 } |
61 | 46 |
62 | 47 |
48 internal void Resolve() { | |
49 if (BeginTransit()) | |
50 CompleteResolve(); | |
51 } | |
52 | |
53 internal void Reject(Exception reason) { | |
54 if (BeginTransit()) { | |
55 m_error = reason; | |
56 m_state = PromiseState.Rejected; | |
57 CompleteTransit(); | |
58 } | |
59 } | |
60 | |
61 | |
63 #region implemented abstract members of AbstractPromise | 62 #region implemented abstract members of AbstractPromise |
64 | 63 |
65 protected override void SignalHandler(HandlerDescriptor handler) { | 64 protected override void SignalHandler(IResolvable handler) { |
66 switch (m_state) { | 65 switch (m_state) { |
67 case PromiseState.Resolved: | 66 case PromiseState.Fulfilled: |
68 handler.SignalSuccess(); | 67 handler.Resolve(); |
69 break; | 68 break; |
70 case PromiseState.Rejected: | 69 case PromiseState.Rejected: |
71 handler.SignalError(RejectReason); | 70 handler.Reject(RejectReason); |
72 break; | 71 break; |
73 default: | 72 default: |
74 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | 73 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); |
75 } | 74 } |
76 } | 75 } |
77 | 76 |
78 protected override Signal GetFulfillSignal() { | 77 protected override Signal GetFulfillSignal() { |
79 var signal = new Signal(); | 78 var next = new ResolvableSignal(); |
80 On(signal.Set, e => signal.Set()); | 79 Then(next); |
81 return signal; | 80 return next.Signal; |
82 } | 81 } |
83 | 82 |
84 #endregion | 83 #endregion |
85 | 84 |
86 protected void CompleteResolve() { | 85 protected void CompleteResolve() { |
87 m_state = PromiseState.Resolved; | 86 m_state = PromiseState.Fulfilled; |
88 CompleteTransit(); | 87 CompleteTransit(); |
89 } | 88 } |
90 | 89 |
91 public Type ResultType { | 90 public Type ResultType { |
92 get { | 91 get { |
93 return typeof(void); | 92 return typeof(void); |
94 } | 93 } |
95 } | 94 } |
96 | 95 |
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 | 96 |
119 protected void Rethrow() { | 97 protected void Rethrow() { |
120 Debug.Assert(m_error != null); | 98 Debug.Assert(m_error != null); |
121 if (m_error is OperationCanceledException) | 99 if (m_error is OperationCanceledException) |
122 throw new OperationCanceledException("Operation cancelled", m_error); | 100 throw new OperationCanceledException("Operation cancelled", m_error); |
123 else | 101 else |
124 throw new TargetInvocationException(m_error); | 102 throw new TargetInvocationException(m_error); |
125 } | 103 } |
126 | 104 |
127 public void On(Action success, Action<Exception> error) { | 105 public void Then(IResolvable next) { |
128 AddHandler(new HandlerDescriptor(success, error)); | 106 AddHandler(next); |
129 } | 107 } |
130 | 108 |
131 public IPromise<T> Cast<T>() { | 109 public IPromise<T> Cast<T>() { |
132 throw new InvalidCastException(); | 110 throw new InvalidCastException(); |
133 } | 111 } |