comparison Implab/Promise.cs @ 9:c82e0dfbb4dd promises

sync
author cin
date Sat, 02 Nov 2013 00:55:47 +0400
parents 7ea9363fef6c
children aa33d0bb8c0c
comparison
equal deleted inserted replaced
8:849075f49d5c 9:c82e0dfbb4dd
46 /// <para> 46 /// <para>
47 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать 47 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать
48 /// только инициатор обещания иначе могут возникнуть противоречия. 48 /// только инициатор обещания иначе могут возникнуть противоречия.
49 /// </para> 49 /// </para>
50 /// </remarks> 50 /// </remarks>
51 public class Promise<T>: IPromise { 51 public class Promise<T> : IPromise {
52 52
53 struct ResultHandlerInfo { 53 struct ResultHandlerInfo {
54 public ResultHandler<T> resultHandler; 54 public ResultHandler<T> resultHandler;
55 public ErrorHandler errorHandler; 55 public ErrorHandler errorHandler;
56 public Action cancelHandler; 56 }
57 } 57
58 58 IPromise m_parent;
59 LinkedList<ResultHandlerInfo> m_handlersChain = new LinkedList<ResultHandlerInfo>(); 59
60 LinkedList<ResultHandlerInfo> m_resultHandlers = new LinkedList<ResultHandlerInfo>();
61 LinkedList<Action> m_cancelHandlers = new LinkedList<Action>();
62
63 object m_lock = new Object();
64 bool m_cancellable;
65
60 PromiseState m_state; 66 PromiseState m_state;
61 bool m_cancellable;
62 T m_result; 67 T m_result;
63 Exception m_error; 68 Exception m_error;
64 IPromise m_parent; 69
65 int m_childrenCount; 70 int m_childrenCount;
66 71
67 public Promise() { 72 public Promise() {
68 m_cancellable = true; 73 m_cancellable = true;
69 } 74 }
70 75
71 public Promise(IPromise parent, bool cancellable) 76 public Promise(IPromise parent, bool cancellable) {
72 {
73 m_cancellable = cancellable; 77 m_cancellable = cancellable;
74 m_parent = parent; 78 m_parent = parent;
75 } 79 }
76 80
77 /// <summary> 81 /// <summary>
95 throw new InvalidOperationException("The promise is already resolved"); 99 throw new InvalidOperationException("The promise is already resolved");
96 m_result = result; 100 m_result = result;
97 m_state = PromiseState.Resolved; 101 m_state = PromiseState.Resolved;
98 } 102 }
99 103
100 ResultHandlerInfo handler; 104 // state has been changed to rejected new handlers can't be added
105
106 foreach (var handler in m_resultHandlers)
107 InvokeHandler(handler);
108
109 /* ResultHandlerInfo handler;
101 while (FetchNextHandler(out handler)) 110 while (FetchNextHandler(out handler))
102 InvokeHandler(handler); 111 InvokeHandler(handler); */
103 } 112 }
104 113
105 /// <summary> 114 /// <summary>
106 /// Выполняет обещание, сообщая об ошибке 115 /// Выполняет обещание, сообщая об ошибке
107 /// </summary> 116 /// </summary>
115 throw new InvalidOperationException("The promise is already resolved"); 124 throw new InvalidOperationException("The promise is already resolved");
116 m_error = error; 125 m_error = error;
117 m_state = PromiseState.Rejected; 126 m_state = PromiseState.Rejected;
118 } 127 }
119 128
120 ResultHandlerInfo handler; 129 // state has been changed to rejected new handlers can't be added
130
131 foreach (var handler in m_resultHandlers)
132 InvokeHandler(handler);
133
134 /*ResultHandlerInfo handler;
121 while (FetchNextHandler(out handler)) 135 while (FetchNextHandler(out handler))
122 InvokeHandler(handler); 136 InvokeHandler(handler);*/
123 } 137 }
124 138
125 /// <summary> 139 /// <summary>
126 /// Отменяет операцию, если это возможно. 140 /// Отменяет операцию, если это возможно.
127 /// </summary> 141 /// </summary>
128 /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns> 142 /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns>
129 public bool Cancel() { 143 public bool Cancel() {
130 lock (this) { 144 return Cancel(true);
131 if (m_state == PromiseState.Unresolved && m_cancellable)
132 {
133 m_state = PromiseState.Cancelled;
134 EventHandler temp = Cancelled;
135
136 if (temp != null)
137 temp(this, new EventArgs());
138
139 return true;
140 } else
141 return false;
142 }
143 } 145 }
144 146
145 /// <summary> 147 /// <summary>
146 /// Добавляет обработчики событий выполнения обещания. 148 /// Добавляет обработчики событий выполнения обещания.
147 /// </summary> 149 /// </summary>
351 handler = default(ResultHandlerInfo); 353 handler = default(ResultHandlerInfo);
352 354
353 lock (this) { 355 lock (this) {
354 Debug.Assert(m_state != PromiseState.Unresolved); 356 Debug.Assert(m_state != PromiseState.Unresolved);
355 357
356 if (m_handlersChain.Count > 0) { 358 if (m_resultHandlers.Count > 0) {
357 handler = m_handlersChain.First.Value; 359 handler = m_resultHandlers.First.Value;
358 m_handlersChain.RemoveFirst(); 360 m_resultHandlers.RemoveFirst();
359 return true; 361 return true;
360 } else { 362 } else {
361 return false; 363 return false;
362 } 364 }
363 } 365 }
366 void AddHandler(ResultHandlerInfo handler) { 368 void AddHandler(ResultHandlerInfo handler) {
367 bool invokeRequired = false; 369 bool invokeRequired = false;
368 370
369 lock (this) { 371 lock (this) {
370 if (m_state == PromiseState.Unresolved) 372 if (m_state == PromiseState.Unresolved)
371 m_handlersChain.AddLast(handler); 373 m_resultHandlers.AddLast(handler);
372 else 374 else
373 invokeRequired = true; 375 invokeRequired = true;
374 } 376 }
375 377
376 // обработчики не должны блокировать сам объект 378 // обработчики не должны блокировать сам объект
393 } catch { } 395 } catch { }
394 } 396 }
395 } 397 }
396 398
397 399
400
401 public bool IsExclusive {
402 get {
403 lock (m_lock) {
404 return m_childrenCount <= 1;
405 }
406 }
407 }
408
409 public PromiseState State {
410 get {
411 lock (m_lock) {
412 return m_state;
413 }
414 }
415 }
416
417 public bool Cancel(bool dependencies) {
418 bool result;
419
420 lock (m_lock) {
421 if (m_state == PromiseState.Unresolved) {
422 m_state = PromiseState.Cancelled;
423 result = true;
424 } else {
425 result = false;
426 }
427 }
428
429 if (dependencies && m_parent != null && m_parent.IsExclusive) {
430 // TODO syncronize IsExclusive, AddHandler, Cancel (maybe CancelExclusive)
431 m_parent.Cancel(true);
432 }
433
434 if (result) {
435 // state has been changed to cancelled, new handlers can't be added
436 foreach (var handler in m_cancelHandlers)
437 handler();
438 }
439
440 return result;
441 }
398 } 442 }
399 } 443 }