248
|
1 using System;
|
|
2 using System.Diagnostics;
|
|
3 using System.Reflection;
|
|
4 using Implab.Parallels;
|
|
5
|
|
6 namespace Implab {
|
|
7 public class Promise<T> : AbstractEvent<IResolvable<T>>, IPromise<T> {
|
|
8
|
|
9 class ResolvableSignal : IResolvable<T> {
|
|
10 public Signal Signal { get; private set; }
|
|
11 public ResolvableSignal() {
|
|
12 Signal = new Signal();
|
|
13 }
|
|
14
|
|
15
|
|
16 public void Reject(Exception error) {
|
|
17 Signal.Set();
|
|
18 }
|
|
19
|
|
20 public void Resolve(T result) {
|
|
21 Signal.Set();
|
|
22 }
|
|
23 }
|
|
24
|
|
25 class ResolvableWrapper : IResolvable<T> {
|
|
26 readonly IResolvable m_resolvable;
|
|
27 public ResolvableWrapper(IResolvable resolvable) {
|
|
28 m_resolvable = resolvable;
|
|
29 }
|
|
30
|
|
31 public void Reject(Exception reason) {
|
|
32 m_resolvable.Reject(reason);
|
|
33 }
|
|
34
|
|
35 public void Resolve(T value) {
|
|
36 m_resolvable.Resolve();
|
|
37 }
|
|
38 }
|
|
39
|
|
40 PromiseState m_state;
|
|
41
|
|
42 T m_result;
|
|
43
|
|
44 Exception m_error;
|
|
45
|
|
46 public bool IsRejected {
|
|
47 get {
|
|
48 return m_state == PromiseState.Rejected;
|
|
49 }
|
|
50 }
|
|
51
|
|
52 public bool IsFulfilled {
|
|
53 get {
|
|
54 return m_state == PromiseState.Fulfilled;
|
|
55 }
|
|
56 }
|
|
57
|
|
58 public Exception RejectReason {
|
|
59 get {
|
|
60 return m_error;
|
|
61 }
|
|
62 }
|
|
63
|
|
64
|
|
65 internal void ResolvePromise(T result) {
|
|
66 if (BeginTransit()) {
|
|
67 m_result = result;
|
|
68 m_state = PromiseState.Fulfilled;
|
|
69 CompleteTransit();
|
|
70 }
|
|
71 }
|
|
72
|
|
73 internal void RejectPromise(Exception reason) {
|
|
74 if (BeginTransit()) {
|
|
75 m_error = reason;
|
|
76 m_state = PromiseState.Rejected;
|
|
77 CompleteTransit();
|
|
78 }
|
|
79 }
|
|
80
|
|
81
|
|
82 #region implemented abstract members of AbstractPromise
|
|
83
|
|
84 protected override void SignalHandler(IResolvable<T> handler) {
|
|
85 switch (m_state) {
|
|
86 case PromiseState.Fulfilled:
|
|
87 handler.Resolve(m_result);
|
|
88 break;
|
|
89 case PromiseState.Rejected:
|
|
90 handler.Reject(RejectReason);
|
|
91 break;
|
|
92 default:
|
|
93 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
|
|
94 }
|
|
95 }
|
|
96
|
|
97 protected void WaitResult(int timeout) {
|
|
98 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
|
|
99 throw new TimeoutException();
|
|
100 }
|
|
101
|
|
102 protected Signal GetFulfillSignal() {
|
|
103 var next = new ResolvableSignal();
|
|
104 Then(next);
|
|
105 return next.Signal;
|
|
106 }
|
|
107
|
|
108 #endregion
|
|
109
|
|
110 public Type ResultType {
|
|
111 get {
|
|
112 return typeof(void);
|
|
113 }
|
|
114 }
|
|
115
|
|
116
|
|
117 protected void Rethrow() {
|
|
118 if (m_error is OperationCanceledException)
|
|
119 throw new OperationCanceledException("Operation cancelled", m_error);
|
|
120 else
|
|
121 throw new TargetInvocationException(m_error);
|
|
122 }
|
|
123
|
|
124 public void Then(IResolvable<T> next) {
|
|
125 AddHandler(next);
|
|
126 }
|
|
127
|
|
128 public void Then(IResolvable next) {
|
|
129 AddHandler(new ResolvableWrapper(next));
|
|
130 }
|
|
131
|
|
132 public IPromise<T2> Cast<T2>() {
|
|
133 return (IPromise<T2>)this;
|
|
134 }
|
|
135
|
|
136 void IPromise.Join() {
|
|
137 Join();
|
|
138 }
|
|
139
|
|
140 void IPromise.Join(int timeout) {
|
|
141 Join(timeout);
|
|
142 }
|
|
143
|
|
144 public T Join() {
|
|
145 WaitResult(-1);
|
|
146 if (IsRejected)
|
|
147 Rethrow();
|
|
148 return m_result;
|
|
149 }
|
|
150
|
|
151 public T Join(int timeout) {
|
|
152 WaitResult(timeout);
|
|
153 if (IsRejected)
|
|
154 Rethrow();
|
|
155 return m_result;
|
|
156 }
|
|
157 }
|
|
158 }
|
|
159
|