concurrent-ruby 1.0.5 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +65 -0
  3. data/Gemfile +39 -0
  4. data/{LICENSE.txt → LICENSE.md} +2 -0
  5. data/README.md +207 -105
  6. data/Rakefile +314 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +306 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent/agent.rb +7 -7
  23. data/lib/concurrent/array.rb +59 -32
  24. data/lib/concurrent/async.rb +4 -4
  25. data/lib/concurrent/atom.rb +9 -9
  26. data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
  27. data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent/atomic/atomic_reference.rb +185 -32
  30. data/lib/concurrent/atomic/count_down_latch.rb +6 -6
  31. data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/concurrent/atomic/event.rb +1 -1
  33. data/lib/concurrent/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/concurrent/atomic/read_write_lock.rb +2 -1
  37. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  38. data/lib/concurrent/atomic/semaphore.rb +8 -8
  39. data/lib/concurrent/atomic/thread_local_var.rb +7 -7
  40. data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
  41. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
  42. data/lib/concurrent/atomics.rb +0 -43
  43. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  44. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
  45. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
  46. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
  47. data/lib/concurrent/concern/dereferenceable.rb +1 -1
  48. data/lib/concurrent/concern/logging.rb +6 -1
  49. data/lib/concurrent/concern/observable.rb +7 -7
  50. data/lib/concurrent/concurrent_ruby.jar +0 -0
  51. data/lib/concurrent/configuration.rb +1 -6
  52. data/lib/concurrent/constants.rb +1 -1
  53. data/lib/concurrent/dataflow.rb +2 -1
  54. data/lib/concurrent/delay.rb +9 -7
  55. data/lib/concurrent/exchanger.rb +21 -25
  56. data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
  57. data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
  58. data/lib/concurrent/executor/executor_service.rb +15 -15
  59. data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
  60. data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
  61. data/lib/concurrent/executor/single_thread_executor.rb +2 -2
  62. data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
  63. data/lib/concurrent/executor/timer_set.rb +1 -1
  64. data/lib/concurrent/future.rb +4 -1
  65. data/lib/concurrent/hash.rb +53 -30
  66. data/lib/concurrent/ivar.rb +5 -6
  67. data/lib/concurrent/map.rb +178 -81
  68. data/lib/concurrent/maybe.rb +1 -1
  69. data/lib/concurrent/mutable_struct.rb +15 -14
  70. data/lib/concurrent/mvar.rb +2 -2
  71. data/lib/concurrent/promise.rb +53 -21
  72. data/lib/concurrent/promises.rb +1936 -0
  73. data/lib/concurrent/re_include.rb +58 -0
  74. data/lib/concurrent/set.rb +66 -0
  75. data/lib/concurrent/settable_struct.rb +1 -0
  76. data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
  77. data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
  78. data/lib/concurrent/synchronization/lockable_object.rb +6 -6
  79. data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
  80. data/lib/concurrent/synchronization/object.rb +8 -4
  81. data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
  82. data/lib/concurrent/synchronization/volatile.rb +11 -9
  83. data/lib/concurrent/synchronization.rb +4 -5
  84. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  85. data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
  86. data/lib/concurrent/timer_task.rb +5 -2
  87. data/lib/concurrent/tuple.rb +1 -1
  88. data/lib/concurrent/tvar.rb +2 -2
  89. data/lib/concurrent/utility/193.rb +17 -0
  90. data/lib/concurrent/utility/at_exit.rb +1 -1
  91. data/lib/concurrent/utility/engine.rb +4 -4
  92. data/lib/concurrent/utility/monotonic_time.rb +3 -3
  93. data/lib/concurrent/utility/native_extension_loader.rb +31 -33
  94. data/lib/concurrent/utility/processor_counter.rb +0 -2
  95. data/lib/concurrent/version.rb +2 -2
  96. data/lib/concurrent-ruby.rb +1 -0
  97. data/lib/concurrent.rb +26 -20
  98. metadata +33 -18
  99. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  100. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  101. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  102. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  103. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  104. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  105. data/lib/concurrent/edge.rb +0 -26
  106. data/lib/concurrent/lazy_register.rb +0 -81
  107. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  108. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  109. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
@@ -0,0 +1,1936 @@
1
+ require 'concurrent/synchronization'
2
+ require 'concurrent/atomic/atomic_boolean'
3
+ require 'concurrent/atomic/atomic_fixnum'
4
+ require 'concurrent/collection/lock_free_stack'
5
+ require 'concurrent/errors'
6
+ require 'concurrent/re_include'
7
+
8
+ module Concurrent
9
+
10
+ # {include:file:docs-source/promises-main.md}
11
+ module Promises
12
+
13
+ # @!macro promises.param.default_executor
14
+ # @param [Executor, :io, :fast] default_executor Instance of an executor or a name of the
15
+ # global executor. Default executor propagates to chained futures unless overridden with
16
+ # executor parameter or changed with {AbstractEventFuture#with_default_executor}.
17
+ #
18
+ # @!macro promises.param.executor
19
+ # @param [Executor, :io, :fast] executor Instance of an executor or a name of the
20
+ # global executor. The task is executed on it, default executor remains unchanged.
21
+ #
22
+ # @!macro promises.param.args
23
+ # @param [Object] args arguments which are passed to the task when it's executed.
24
+ # (It might be prepended with other arguments, see the @yeild section).
25
+ #
26
+ # @!macro promises.shortcut.on
27
+ # Shortcut of {#$0_on} with default `:io` executor supplied.
28
+ # @see #$0_on
29
+ #
30
+ # @!macro promises.shortcut.using
31
+ # Shortcut of {#$0_using} with default `:io` executor supplied.
32
+ # @see #$0_using
33
+ #
34
+ # @!macro promise.param.task-future
35
+ # @yieldreturn will become result of the returned Future.
36
+ # Its returned value becomes {Future#value} fulfilling it,
37
+ # raised exception becomes {Future#reason} rejecting it.
38
+ #
39
+ # @!macro promise.param.callback
40
+ # @yieldreturn is forgotten.
41
+
42
+ # Container of all {Future}, {Event} factory methods. They are never constructed directly with
43
+ # new.
44
+ module FactoryMethods
45
+ extend ReInclude
46
+
47
+ module Configuration
48
+ # @return [Executor, :io, :fast] the executor which is used when none is supplied
49
+ # to a factory method. The method can be overridden in the receivers of
50
+ # `include FactoryMethod`
51
+ def default_executor
52
+ :io
53
+ end
54
+ end
55
+
56
+ include Configuration
57
+
58
+ # @!macro promises.shortcut.on
59
+ # @return [ResolvableEvent]
60
+ def resolvable_event
61
+ resolvable_event_on default_executor
62
+ end
63
+
64
+ # Created resolvable event, user is responsible for resolving the event once by
65
+ # {Promises::ResolvableEvent#resolve}.
66
+ #
67
+ # @!macro promises.param.default_executor
68
+ # @return [ResolvableEvent]
69
+ def resolvable_event_on(default_executor = self.default_executor)
70
+ ResolvableEventPromise.new(default_executor).future
71
+ end
72
+
73
+ # @!macro promises.shortcut.on
74
+ # @return [ResolvableFuture]
75
+ def resolvable_future
76
+ resolvable_future_on default_executor
77
+ end
78
+
79
+ # Creates resolvable future, user is responsible for resolving the future once by
80
+ # {Promises::ResolvableFuture#resolve}, {Promises::ResolvableFuture#fulfill},
81
+ # or {Promises::ResolvableFuture#reject}
82
+ #
83
+ # @!macro promises.param.default_executor
84
+ # @return [ResolvableFuture]
85
+ def resolvable_future_on(default_executor = self.default_executor)
86
+ ResolvableFuturePromise.new(default_executor).future
87
+ end
88
+
89
+ # @!macro promises.shortcut.on
90
+ # @return [Future]
91
+ def future(*args, &task)
92
+ future_on(default_executor, *args, &task)
93
+ end
94
+
95
+ # @!macro promises.future-on1
96
+ # Constructs new Future which will be resolved after block is evaluated on default executor.
97
+ # Evaluation begins immediately.
98
+ #
99
+ # @!macro promises.future-on2
100
+ # @!macro promises.param.default_executor
101
+ # @!macro promises.param.args
102
+ # @yield [*args] to the task.
103
+ # @!macro promise.param.task-future
104
+ # @return [Future]
105
+ def future_on(default_executor, *args, &task)
106
+ ImmediateEventPromise.new(default_executor).future.then(*args, &task)
107
+ end
108
+
109
+ # Creates resolved future with will be either fulfilled with the given value or rejection with
110
+ # the given reason.
111
+ #
112
+ # @!macro promises.param.default_executor
113
+ # @return [Future]
114
+ def resolved_future(fulfilled, value, reason, default_executor = self.default_executor)
115
+ ImmediateFuturePromise.new(default_executor, fulfilled, value, reason).future
116
+ end
117
+
118
+ # Creates resolved future with will be fulfilled with the given value.
119
+ #
120
+ # @!macro promises.param.default_executor
121
+ # @return [Future]
122
+ def fulfilled_future(value, default_executor = self.default_executor)
123
+ resolved_future true, value, nil, default_executor
124
+ end
125
+
126
+ # Creates resolved future with will be rejected with the given reason.
127
+ #
128
+ # @!macro promises.param.default_executor
129
+ # @return [Future]
130
+ def rejected_future(reason, default_executor = self.default_executor)
131
+ resolved_future false, nil, reason, default_executor
132
+ end
133
+
134
+ # Creates resolved event.
135
+ #
136
+ # @!macro promises.param.default_executor
137
+ # @return [Event]
138
+ def resolved_event(default_executor = self.default_executor)
139
+ ImmediateEventPromise.new(default_executor).event
140
+ end
141
+
142
+ # General constructor. Behaves differently based on the argument's type. It's provided for convenience
143
+ # but it's better to be explicit.
144
+ #
145
+ # @see rejected_future, resolved_event, fulfilled_future
146
+ # @!macro promises.param.default_executor
147
+ # @return [Event, Future]
148
+ #
149
+ # @overload create(nil, default_executor = self.default_executor)
150
+ # @param [nil] nil
151
+ # @return [Event] resolved event.
152
+ #
153
+ # @overload create(a_future, default_executor = self.default_executor)
154
+ # @param [Future] a_future
155
+ # @return [Future] a future which will be resolved when a_future is.
156
+ #
157
+ # @overload create(an_event, default_executor = self.default_executor)
158
+ # @param [Event] an_event
159
+ # @return [Event] an event which will be resolved when an_event is.
160
+ #
161
+ # @overload create(exception, default_executor = self.default_executor)
162
+ # @param [Exception] exception
163
+ # @return [Future] a rejected future with the exception as its reason.
164
+ #
165
+ # @overload create(value, default_executor = self.default_executor)
166
+ # @param [Object] value when none of the above overloads fits
167
+ # @return [Future] a fulfilled future with the value.
168
+ def make_future(argument = nil, default_executor = self.default_executor)
169
+ case argument
170
+ when AbstractEventFuture
171
+ # returning wrapper would change nothing
172
+ argument
173
+ when Exception
174
+ rejected_future argument, default_executor
175
+ when nil
176
+ resolved_event default_executor
177
+ else
178
+ fulfilled_future argument, default_executor
179
+ end
180
+ end
181
+
182
+ # @!macro promises.shortcut.on
183
+ # @return [Future]
184
+ def delay(*args, &task)
185
+ delay_on default_executor, *args, &task
186
+ end
187
+
188
+ # @!macro promises.future-on1
189
+ # The task will be evaluated only after the future is touched, see {AbstractEventFuture#touch}
190
+ #
191
+ # @!macro promises.future-on2
192
+ def delay_on(default_executor, *args, &task)
193
+ DelayPromise.new(default_executor).event.chain(*args, &task)
194
+ end
195
+
196
+ # @!macro promises.shortcut.on
197
+ # @return [Future]
198
+ def schedule(intended_time, *args, &task)
199
+ schedule_on default_executor, intended_time, *args, &task
200
+ end
201
+
202
+ # @!macro promises.future-on1
203
+ # The task is planned for execution in intended_time.
204
+ #
205
+ # @!macro promises.future-on2
206
+ # @!macro promises.param.intended_time
207
+ # @param [Numeric, Time] intended_time `Numeric` means to run in `intended_time` seconds.
208
+ # `Time` means to run on `intended_time`.
209
+ def schedule_on(default_executor, intended_time, *args, &task)
210
+ ScheduledPromise.new(default_executor, intended_time).event.chain(*args, &task)
211
+ end
212
+
213
+ # @!macro promises.shortcut.on
214
+ # @return [Future]
215
+ def zip_futures(*futures_and_or_events)
216
+ zip_futures_on default_executor, *futures_and_or_events
217
+ end
218
+
219
+ # Creates new future which is resolved after all futures_and_or_events are resolved.
220
+ # Its value is array of zipped future values. Its reason is array of reasons for rejection.
221
+ # If there is an error it rejects.
222
+ # @!macro promises.event-conversion
223
+ # If event is supplied, which does not have value and can be only resolved, it's
224
+ # represented as `:fulfilled` with value `nil`.
225
+ #
226
+ # @!macro promises.param.default_executor
227
+ # @param [AbstractEventFuture] futures_and_or_events
228
+ # @return [Future]
229
+ def zip_futures_on(default_executor, *futures_and_or_events)
230
+ ZipFuturesPromise.new_blocked_by(futures_and_or_events, default_executor).future
231
+ end
232
+
233
+ alias_method :zip, :zip_futures
234
+
235
+ # @!macro promises.shortcut.on
236
+ # @return [Event]
237
+ def zip_events(*futures_and_or_events)
238
+ zip_events_on default_executor, *futures_and_or_events
239
+ end
240
+
241
+ # Creates new event which is resolved after all futures_and_or_events are resolved.
242
+ # (Future is resolved when fulfilled or rejected.)
243
+ #
244
+ # @!macro promises.param.default_executor
245
+ # @param [AbstractEventFuture] futures_and_or_events
246
+ # @return [Event]
247
+ def zip_events_on(default_executor, *futures_and_or_events)
248
+ ZipEventsPromise.new_blocked_by(futures_and_or_events, default_executor).event
249
+ end
250
+
251
+ # @!macro promises.shortcut.on
252
+ # @return [Future]
253
+ def any_resolved_future(*futures_and_or_events)
254
+ any_resolved_future_on default_executor, *futures_and_or_events
255
+ end
256
+
257
+ alias_method :any, :any_resolved_future
258
+
259
+ # Creates new future which is resolved after first futures_and_or_events is resolved.
260
+ # Its result equals result of the first resolved future.
261
+ # @!macro promises.any-touch
262
+ # If resolved it does not propagate {AbstractEventFuture#touch}, leaving delayed
263
+ # futures un-executed if they are not required any more.
264
+ # @!macro promises.event-conversion
265
+ #
266
+ # @!macro promises.param.default_executor
267
+ # @param [AbstractEventFuture] futures_and_or_events
268
+ # @return [Future]
269
+ def any_resolved_future_on(default_executor, *futures_and_or_events)
270
+ AnyResolvedFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future
271
+ end
272
+
273
+ # @!macro promises.shortcut.on
274
+ # @return [Future]
275
+ def any_fulfilled_future(*futures_and_or_events)
276
+ any_fulfilled_future_on default_executor, *futures_and_or_events
277
+ end
278
+
279
+ # Creates new future which is resolved after first of futures_and_or_events is fulfilled.
280
+ # Its result equals result of the first resolved future or if all futures_and_or_events reject,
281
+ # it has reason of the last resolved future.
282
+ # @!macro promises.any-touch
283
+ # @!macro promises.event-conversion
284
+ #
285
+ # @!macro promises.param.default_executor
286
+ # @param [AbstractEventFuture] futures_and_or_events
287
+ # @return [Future]
288
+ def any_fulfilled_future_on(default_executor, *futures_and_or_events)
289
+ AnyFulfilledFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future
290
+ end
291
+
292
+ # @!macro promises.shortcut.on
293
+ # @return [Future]
294
+ def any_event(*futures_and_or_events)
295
+ any_event_on default_executor, *futures_and_or_events
296
+ end
297
+
298
+ # Creates new event which becomes resolved after first of the futures_and_or_events resolves.
299
+ # @!macro promises.any-touch
300
+ #
301
+ # @!macro promises.param.default_executor
302
+ # @param [AbstractEventFuture] futures_and_or_events
303
+ # @return [Event]
304
+ def any_event_on(default_executor, *futures_and_or_events)
305
+ AnyResolvedEventPromise.new_blocked_by(futures_and_or_events, default_executor).event
306
+ end
307
+
308
+ # TODO consider adding first(count, *futures)
309
+ # TODO consider adding zip_by(slice, *futures) processing futures in slices
310
+ # TODO or rather a generic aggregator taking a function
311
+ end
312
+
313
+ module InternalStates
314
+ # @private
315
+ class State
316
+ def resolved?
317
+ raise NotImplementedError
318
+ end
319
+
320
+ def to_sym
321
+ raise NotImplementedError
322
+ end
323
+ end
324
+
325
+ private_constant :State
326
+
327
+ # @private
328
+ class Pending < State
329
+ def resolved?
330
+ false
331
+ end
332
+
333
+ def to_sym
334
+ :pending
335
+ end
336
+ end
337
+
338
+ private_constant :Pending
339
+
340
+ # @private
341
+ class ResolvedWithResult < State
342
+ def resolved?
343
+ true
344
+ end
345
+
346
+ def to_sym
347
+ :resolved
348
+ end
349
+
350
+ def result
351
+ [fulfilled?, value, reason]
352
+ end
353
+
354
+ def fulfilled?
355
+ raise NotImplementedError
356
+ end
357
+
358
+ def value
359
+ raise NotImplementedError
360
+ end
361
+
362
+ def reason
363
+ raise NotImplementedError
364
+ end
365
+
366
+ def apply
367
+ raise NotImplementedError
368
+ end
369
+ end
370
+
371
+ private_constant :ResolvedWithResult
372
+
373
+ # @private
374
+ class Fulfilled < ResolvedWithResult
375
+
376
+ def initialize(value)
377
+ @Value = value
378
+ end
379
+
380
+ def fulfilled?
381
+ true
382
+ end
383
+
384
+ def apply(args, block)
385
+ block.call value, *args
386
+ end
387
+
388
+ def value
389
+ @Value
390
+ end
391
+
392
+ def reason
393
+ nil
394
+ end
395
+
396
+ def to_sym
397
+ :fulfilled
398
+ end
399
+ end
400
+
401
+ private_constant :Fulfilled
402
+
403
+ # @private
404
+ class FulfilledArray < Fulfilled
405
+ def apply(args, block)
406
+ block.call(*value, *args)
407
+ end
408
+ end
409
+
410
+ private_constant :FulfilledArray
411
+
412
+ # @private
413
+ class Rejected < ResolvedWithResult
414
+ def initialize(reason)
415
+ @Reason = reason
416
+ end
417
+
418
+ def fulfilled?
419
+ false
420
+ end
421
+
422
+ def value
423
+ nil
424
+ end
425
+
426
+ def reason
427
+ @Reason
428
+ end
429
+
430
+ def to_sym
431
+ :rejected
432
+ end
433
+
434
+ def apply(args, block)
435
+ block.call reason, *args
436
+ end
437
+ end
438
+
439
+ private_constant :Rejected
440
+
441
+ # @private
442
+ class PartiallyRejected < ResolvedWithResult
443
+ def initialize(value, reason)
444
+ super()
445
+ @Value = value
446
+ @Reason = reason
447
+ end
448
+
449
+ def fulfilled?
450
+ false
451
+ end
452
+
453
+ def to_sym
454
+ :rejected
455
+ end
456
+
457
+ def value
458
+ @Value
459
+ end
460
+
461
+ def reason
462
+ @Reason
463
+ end
464
+
465
+ def apply(args, block)
466
+ block.call(*reason, *args)
467
+ end
468
+ end
469
+
470
+ private_constant :PartiallyRejected
471
+
472
+ PENDING = Pending.new
473
+ RESOLVED = Fulfilled.new(nil)
474
+
475
+ def RESOLVED.to_sym
476
+ :resolved
477
+ end
478
+
479
+ private_constant :PENDING, :RESOLVED
480
+ end
481
+
482
+ private_constant :InternalStates
483
+
484
+ # Common ancestor of {Event} and {Future} classes, many shared methods are defined here.
485
+ class AbstractEventFuture < Synchronization::Object
486
+ safe_initialization!
487
+ private(*attr_atomic(:internal_state) - [:internal_state])
488
+
489
+ include InternalStates
490
+
491
+ def initialize(promise, default_executor)
492
+ super()
493
+ @Lock = Mutex.new
494
+ @Condition = ConditionVariable.new
495
+ @Promise = promise
496
+ @DefaultExecutor = default_executor
497
+ @Callbacks = LockFreeStack.new
498
+ @Waiters = AtomicFixnum.new 0
499
+ self.internal_state = PENDING
500
+ end
501
+
502
+ private :initialize
503
+
504
+ # @!macro promises.shortcut.event-future
505
+ # @see Event#$0
506
+ # @see Future#$0
507
+
508
+ # @!macro promises.param.timeout
509
+ # @param [Numeric] timeout the maximum time in second to wait.
510
+
511
+ # @!macro promises.warn.blocks
512
+ # @note This function potentially blocks current thread until the Future is resolved.
513
+ # Be careful it can deadlock. Try to chain instead.
514
+
515
+ # Returns its state.
516
+ # @return [Symbol]
517
+ #
518
+ # @overload an_event.state
519
+ # @return [:pending, :resolved]
520
+ # @overload a_future.state
521
+ # Both :fulfilled, :rejected implies :resolved.
522
+ # @return [:pending, :fulfilled, :rejected]
523
+ def state
524
+ internal_state.to_sym
525
+ end
526
+
527
+ # Is it in pending state?
528
+ # @return [Boolean]
529
+ def pending?
530
+ !internal_state.resolved?
531
+ end
532
+
533
+ # Is it in resolved state?
534
+ # @return [Boolean]
535
+ def resolved?
536
+ internal_state.resolved?
537
+ end
538
+
539
+ # Propagates touch. Requests all the delayed futures, which it depends on, to be
540
+ # executed. This method is called by any other method requiring resolved state, like {#wait}.
541
+ # @return [self]
542
+ def touch
543
+ @Promise.touch
544
+ self
545
+ end
546
+
547
+ # @!macro promises.touches
548
+ # Calls {AbstractEventFuture#touch}.
549
+
550
+ # @!macro promises.method.wait
551
+ # Wait (block the Thread) until receiver is {#resolved?}.
552
+ # @!macro promises.touches
553
+ #
554
+ # @!macro promises.warn.blocks
555
+ # @!macro promises.param.timeout
556
+ # @return [Future, true, false] self implies timeout was not used, true implies timeout was used
557
+ # and it was resolved, false implies it was not resolved within timeout.
558
+ def wait(timeout = nil)
559
+ result = wait_until_resolved(timeout)
560
+ timeout ? result : self
561
+ end
562
+
563
+ # Returns default executor.
564
+ # @return [Executor] default executor
565
+ # @see #with_default_executor
566
+ # @see FactoryMethods#future_on
567
+ # @see FactoryMethods#resolvable_future
568
+ # @see FactoryMethods#any_fulfilled_future_on
569
+ # @see similar
570
+ def default_executor
571
+ @DefaultExecutor
572
+ end
573
+
574
+ # @!macro promises.shortcut.on
575
+ # @return [Future]
576
+ def chain(*args, &task)
577
+ chain_on @DefaultExecutor, *args, &task
578
+ end
579
+
580
+ # Chains the task to be executed asynchronously on executor after it is resolved.
581
+ #
582
+ # @!macro promises.param.executor
583
+ # @!macro promises.param.args
584
+ # @return [Future]
585
+ # @!macro promise.param.task-future
586
+ #
587
+ # @overload an_event.chain_on(executor, *args, &task)
588
+ # @yield [*args] to the task.
589
+ # @overload a_future.chain_on(executor, *args, &task)
590
+ # @yield [fulfilled, value, reason, *args] to the task.
591
+ # @yieldparam [true, false] fulfilled
592
+ # @yieldparam [Object] value
593
+ # @yieldparam [Exception] reason
594
+ def chain_on(executor, *args, &task)
595
+ ChainPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
596
+ end
597
+
598
+ # @return [String] Short string representation.
599
+ def to_s
600
+ format '%s %s>', super[0..-2], state
601
+ end
602
+
603
+ alias_method :inspect, :to_s
604
+
605
+ # Resolves the resolvable when receiver is resolved.
606
+ #
607
+ # @param [Resolvable] resolvable
608
+ # @return [self]
609
+ def chain_resolvable(resolvable)
610
+ on_resolution! { resolvable.resolve_with internal_state }
611
+ end
612
+
613
+ alias_method :tangle, :chain_resolvable
614
+
615
+ # @!macro promises.shortcut.using
616
+ # @return [self]
617
+ def on_resolution(*args, &callback)
618
+ on_resolution_using @DefaultExecutor, *args, &callback
619
+ end
620
+
621
+ # Stores the callback to be executed synchronously on resolving thread after it is
622
+ # resolved.
623
+ #
624
+ # @!macro promises.param.args
625
+ # @!macro promise.param.callback
626
+ # @return [self]
627
+ #
628
+ # @overload an_event.on_resolution!(*args, &callback)
629
+ # @yield [*args] to the callback.
630
+ # @overload a_future.on_resolution!(*args, &callback)
631
+ # @yield [fulfilled, value, reason, *args] to the callback.
632
+ # @yieldparam [true, false] fulfilled
633
+ # @yieldparam [Object] value
634
+ # @yieldparam [Exception] reason
635
+ def on_resolution!(*args, &callback)
636
+ add_callback :callback_on_resolution, args, callback
637
+ end
638
+
639
+ # Stores the callback to be executed asynchronously on executor after it is resolved.
640
+ #
641
+ # @!macro promises.param.executor
642
+ # @!macro promises.param.args
643
+ # @!macro promise.param.callback
644
+ # @return [self]
645
+ #
646
+ # @overload an_event.on_resolution_using(executor, *args, &callback)
647
+ # @yield [*args] to the callback.
648
+ # @overload a_future.on_resolution_using(executor, *args, &callback)
649
+ # @yield [fulfilled, value, reason, *args] to the callback.
650
+ # @yieldparam [true, false] fulfilled
651
+ # @yieldparam [Object] value
652
+ # @yieldparam [Exception] reason
653
+ def on_resolution_using(executor, *args, &callback)
654
+ add_callback :async_callback_on_resolution, executor, args, callback
655
+ end
656
+
657
+ # @!macro promises.method.with_default_executor
658
+ # Crates new object with same class with the executor set as its new default executor.
659
+ # Any futures depending on it will use the new default executor.
660
+ # @!macro promises.shortcut.event-future
661
+ # @abstract
662
+ # @return [AbstractEventFuture]
663
+ def with_default_executor(executor)
664
+ raise NotImplementedError
665
+ end
666
+
667
+ # @!visibility private
668
+ def resolve_with(state, raise_on_reassign = true)
669
+ if compare_and_set_internal_state(PENDING, state)
670
+ # go to synchronized block only if there were waiting threads
671
+ @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0
672
+ call_callbacks state
673
+ else
674
+ return rejected_resolution(raise_on_reassign, state)
675
+ end
676
+ self
677
+ end
678
+
679
+ # For inspection.
680
+ # @!visibility private
681
+ # @return [Array<AbstractPromise>]
682
+ def blocks
683
+ @Callbacks.each_with_object([]) do |(method, args), promises|
684
+ promises.push(args[0]) if method == :callback_notify_blocked
685
+ end
686
+ end
687
+
688
+ # For inspection.
689
+ # @!visibility private
690
+ def callbacks
691
+ @Callbacks.each.to_a
692
+ end
693
+
694
+ # For inspection.
695
+ # @!visibility private
696
+ def promise
697
+ @Promise
698
+ end
699
+
700
+ # For inspection.
701
+ # @!visibility private
702
+ def touched?
703
+ promise.touched?
704
+ end
705
+
706
+ # For inspection.
707
+ # @!visibility private
708
+ def waiting_threads
709
+ @Waiters.each.to_a
710
+ end
711
+
712
+ # @!visibility private
713
+ def add_callback_notify_blocked(promise, index)
714
+ add_callback :callback_notify_blocked, promise, index
715
+ end
716
+
717
+ # @!visibility private
718
+ def add_callback_clear_delayed_node(node)
719
+ add_callback(:callback_clear_delayed_node, node)
720
+ end
721
+
722
+ private
723
+
724
+ def add_callback(method, *args)
725
+ state = internal_state
726
+ if state.resolved?
727
+ call_callback method, state, args
728
+ else
729
+ @Callbacks.push [method, args]
730
+ state = internal_state
731
+ # take back if it was resolved in the meanwhile
732
+ call_callbacks state if state.resolved?
733
+ end
734
+ self
735
+ end
736
+
737
+ def callback_clear_delayed_node(state, node)
738
+ node.value = nil
739
+ end
740
+
741
+ # @return [Boolean]
742
+ def wait_until_resolved(timeout)
743
+ return true if resolved?
744
+
745
+ touch
746
+
747
+ @Lock.synchronize do
748
+ @Waiters.increment
749
+ begin
750
+ unless resolved?
751
+ @Condition.wait @Lock, timeout
752
+ end
753
+ ensure
754
+ # JRuby may raise ConcurrencyError
755
+ @Waiters.decrement
756
+ end
757
+ end
758
+ resolved?
759
+ end
760
+
761
+ def call_callback(method, state, args)
762
+ self.send method, state, *args
763
+ end
764
+
765
+ def call_callbacks(state)
766
+ method, args = @Callbacks.pop
767
+ while method
768
+ call_callback method, state, args
769
+ method, args = @Callbacks.pop
770
+ end
771
+ end
772
+
773
+ def with_async(executor, *args, &block)
774
+ Concurrent.executor(executor).post(*args, &block)
775
+ end
776
+
777
+ def async_callback_on_resolution(state, executor, args, callback)
778
+ with_async(executor, state, args, callback) do |st, ar, cb|
779
+ callback_on_resolution st, ar, cb
780
+ end
781
+ end
782
+
783
+ def callback_notify_blocked(state, promise, index)
784
+ promise.on_blocker_resolution self, index
785
+ end
786
+ end
787
+
788
+ # Represents an event which will happen in future (will be resolved). The event is either
789
+ # pending or resolved. It should be always resolved. Use {Future} to communicate rejections and
790
+ # cancellation.
791
+ class Event < AbstractEventFuture
792
+
793
+ alias_method :then, :chain
794
+
795
+
796
+ # @!macro promises.method.zip
797
+ # Creates a new event or a future which will be resolved when receiver and other are.
798
+ # Returns an event if receiver and other are events, otherwise returns a future.
799
+ # If just one of the parties is Future then the result
800
+ # of the returned future is equal to the result of the supplied future. If both are futures
801
+ # then the result is as described in {FactoryMethods#zip_futures_on}.
802
+ #
803
+ # @return [Future, Event]
804
+ def zip(other)
805
+ if other.is_a?(Future)
806
+ ZipFutureEventPromise.new_blocked_by2(other, self, @DefaultExecutor).future
807
+ else
808
+ ZipEventEventPromise.new_blocked_by2(self, other, @DefaultExecutor).event
809
+ end
810
+ end
811
+
812
+ alias_method :&, :zip
813
+
814
+ # Creates a new event which will be resolved when the first of receiver, `event_or_future`
815
+ # resolves.
816
+ #
817
+ # @return [Event]
818
+ def any(event_or_future)
819
+ AnyResolvedEventPromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).event
820
+ end
821
+
822
+ alias_method :|, :any
823
+
824
+ # Creates new event dependent on receiver which will not evaluate until touched, see {#touch}.
825
+ # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated.
826
+ #
827
+ # @return [Event]
828
+ def delay
829
+ event = DelayPromise.new(@DefaultExecutor).event
830
+ ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event
831
+ end
832
+
833
+ # @!macro promise.method.schedule
834
+ # Creates new event dependent on receiver scheduled to execute on/in intended_time.
835
+ # In time is interpreted from the moment the receiver is resolved, therefore it inserts
836
+ # delay into the chain.
837
+ #
838
+ # @!macro promises.param.intended_time
839
+ # @return [Event]
840
+ def schedule(intended_time)
841
+ chain do
842
+ event = ScheduledPromise.new(@DefaultExecutor, intended_time).event
843
+ ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event
844
+ end.flat_event
845
+ end
846
+
847
+ # Converts event to a future. The future is fulfilled when the event is resolved, the future may never fail.
848
+ #
849
+ # @return [Future]
850
+ def to_future
851
+ future = Promises.resolvable_future
852
+ ensure
853
+ chain_resolvable(future)
854
+ end
855
+
856
+ # Returns self, since this is event
857
+ # @return [Event]
858
+ def to_event
859
+ self
860
+ end
861
+
862
+ # @!macro promises.method.with_default_executor
863
+ # @return [Event]
864
+ def with_default_executor(executor)
865
+ EventWrapperPromise.new_blocked_by1(self, executor).event
866
+ end
867
+
868
+ private
869
+
870
+ def rejected_resolution(raise_on_reassign, state)
871
+ Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign
872
+ return false
873
+ end
874
+
875
+ def callback_on_resolution(state, args, callback)
876
+ callback.call(*args)
877
+ end
878
+ end
879
+
880
+ # Represents a value which will become available in future. May reject with a reason instead,
881
+ # e.g. when the tasks raises an exception.
882
+ class Future < AbstractEventFuture
883
+
884
+ # Is it in fulfilled state?
885
+ # @return [Boolean]
886
+ def fulfilled?
887
+ state = internal_state
888
+ state.resolved? && state.fulfilled?
889
+ end
890
+
891
+ # Is it in rejected state?
892
+ # @return [Boolean]
893
+ def rejected?
894
+ state = internal_state
895
+ state.resolved? && !state.fulfilled?
896
+ end
897
+
898
+ # @!macro promises.warn.nil
899
+ # @note Make sure returned `nil` is not confused with timeout, no value when rejected,
900
+ # no reason when fulfilled, etc.
901
+ # Use more exact methods if needed, like {#wait}, {#value!}, {#result}, etc.
902
+
903
+ # @!macro promises.method.value
904
+ # Return value of the future.
905
+ # @!macro promises.touches
906
+ #
907
+ # @!macro promises.warn.blocks
908
+ # @!macro promises.warn.nil
909
+ # @!macro promises.param.timeout
910
+ # @return [Object, nil] the value of the Future when fulfilled, nil on timeout or rejection.
911
+ def value(timeout = nil)
912
+ internal_state.value if wait_until_resolved timeout
913
+ end
914
+
915
+ # Returns reason of future's rejection.
916
+ # @!macro promises.touches
917
+ #
918
+ # @!macro promises.warn.blocks
919
+ # @!macro promises.warn.nil
920
+ # @!macro promises.param.timeout
921
+ # @return [Exception, nil] nil on timeout or fulfillment.
922
+ def reason(timeout = nil)
923
+ internal_state.reason if wait_until_resolved timeout
924
+ end
925
+
926
+ # Returns triplet fulfilled?, value, reason.
927
+ # @!macro promises.touches
928
+ #
929
+ # @!macro promises.warn.blocks
930
+ # @!macro promises.param.timeout
931
+ # @return [Array(Boolean, Object, Exception), nil] triplet of fulfilled?, value, reason, or nil
932
+ # on timeout.
933
+ def result(timeout = nil)
934
+ internal_state.result if wait_until_resolved timeout
935
+ end
936
+
937
+ # @!macro promises.method.wait
938
+ # @raise [Exception] {#reason} on rejection
939
+ def wait!(timeout = nil)
940
+ result = wait_until_resolved!(timeout)
941
+ timeout ? result : self
942
+ end
943
+
944
+ # @!macro promises.method.value
945
+ # @return [Object, nil] the value of the Future when fulfilled, nil on timeout.
946
+ # @raise [Exception] {#reason} on rejection
947
+ def value!(timeout = nil)
948
+ internal_state.value if wait_until_resolved! timeout
949
+ end
950
+
951
+ # Allows rejected Future to be risen with `raise` method.
952
+ # @example
953
+ # raise Promises.rejected_future(StandardError.new("boom"))
954
+ # @raise [StandardError] when raising not rejected future
955
+ # @return [Exception]
956
+ def exception(*args)
957
+ raise Concurrent::Error, 'it is not rejected' unless rejected?
958
+ reason = Array(internal_state.reason).flatten.compact
959
+ if reason.size > 1
960
+ ex = Concurrent::MultipleErrors.new reason
961
+ ex.set_backtrace(caller)
962
+ ex
963
+ else
964
+ ex = reason[0].clone.exception(*args)
965
+ ex.set_backtrace Array(ex.backtrace) + caller
966
+ ex
967
+ end
968
+ end
969
+
970
+ # @!macro promises.shortcut.on
971
+ # @return [Future]
972
+ def then(*args, &task)
973
+ then_on @DefaultExecutor, *args, &task
974
+ end
975
+
976
+ # Chains the task to be executed asynchronously on executor after it fulfills. Does not run
977
+ # the task if it rejects. It will resolve though, triggering any dependent futures.
978
+ #
979
+ # @!macro promises.param.executor
980
+ # @!macro promises.param.args
981
+ # @!macro promise.param.task-future
982
+ # @return [Future]
983
+ # @yield [value, *args] to the task.
984
+ def then_on(executor, *args, &task)
985
+ ThenPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
986
+ end
987
+
988
+ # @!macro promises.shortcut.on
989
+ # @return [Future]
990
+ def rescue(*args, &task)
991
+ rescue_on @DefaultExecutor, *args, &task
992
+ end
993
+
994
+ # Chains the task to be executed asynchronously on executor after it rejects. Does not run
995
+ # the task if it fulfills. It will resolve though, triggering any dependent futures.
996
+ #
997
+ # @!macro promises.param.executor
998
+ # @!macro promises.param.args
999
+ # @!macro promise.param.task-future
1000
+ # @return [Future]
1001
+ # @yield [reason, *args] to the task.
1002
+ def rescue_on(executor, *args, &task)
1003
+ RescuePromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
1004
+ end
1005
+
1006
+ # @!macro promises.method.zip
1007
+ # @return [Future]
1008
+ def zip(other)
1009
+ if other.is_a?(Future)
1010
+ ZipFuturesPromise.new_blocked_by2(self, other, @DefaultExecutor).future
1011
+ else
1012
+ ZipFutureEventPromise.new_blocked_by2(self, other, @DefaultExecutor).future
1013
+ end
1014
+ end
1015
+
1016
+ alias_method :&, :zip
1017
+
1018
+ # Creates a new event which will be resolved when the first of receiver, `event_or_future`
1019
+ # resolves. Returning future will have value nil if event_or_future is event and resolves
1020
+ # first.
1021
+ #
1022
+ # @return [Future]
1023
+ def any(event_or_future)
1024
+ AnyResolvedFuturePromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).future
1025
+ end
1026
+
1027
+ alias_method :|, :any
1028
+
1029
+ # Creates new future dependent on receiver which will not evaluate until touched, see {#touch}.
1030
+ # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated.
1031
+ #
1032
+ # @return [Future]
1033
+ def delay
1034
+ event = DelayPromise.new(@DefaultExecutor).event
1035
+ ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future
1036
+ end
1037
+
1038
+ # @!macro promise.method.schedule
1039
+ # @return [Future]
1040
+ def schedule(intended_time)
1041
+ chain do
1042
+ event = ScheduledPromise.new(@DefaultExecutor, intended_time).event
1043
+ ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future
1044
+ end.flat
1045
+ end
1046
+
1047
+ # @!macro promises.method.with_default_executor
1048
+ # @return [Future]
1049
+ def with_default_executor(executor)
1050
+ FutureWrapperPromise.new_blocked_by1(self, executor).future
1051
+ end
1052
+
1053
+ # Creates new future which will have result of the future returned by receiver. If receiver
1054
+ # rejects it will have its rejection.
1055
+ #
1056
+ # @param [Integer] level how many levels of futures should flatten
1057
+ # @return [Future]
1058
+ def flat_future(level = 1)
1059
+ FlatFuturePromise.new_blocked_by1(self, level, @DefaultExecutor).future
1060
+ end
1061
+
1062
+ alias_method :flat, :flat_future
1063
+
1064
+ # Creates new event which will be resolved when the returned event by receiver is.
1065
+ # Be careful if the receiver rejects it will just resolve since Event does not hold reason.
1066
+ #
1067
+ # @return [Event]
1068
+ def flat_event
1069
+ FlatEventPromise.new_blocked_by1(self, @DefaultExecutor).event
1070
+ end
1071
+
1072
+ # @!macro promises.shortcut.using
1073
+ # @return [self]
1074
+ def on_fulfillment(*args, &callback)
1075
+ on_fulfillment_using @DefaultExecutor, *args, &callback
1076
+ end
1077
+
1078
+ # Stores the callback to be executed synchronously on resolving thread after it is
1079
+ # fulfilled. Does nothing on rejection.
1080
+ #
1081
+ # @!macro promises.param.args
1082
+ # @!macro promise.param.callback
1083
+ # @return [self]
1084
+ # @yield [value, *args] to the callback.
1085
+ def on_fulfillment!(*args, &callback)
1086
+ add_callback :callback_on_fulfillment, args, callback
1087
+ end
1088
+
1089
+ # Stores the callback to be executed asynchronously on executor after it is
1090
+ # fulfilled. Does nothing on rejection.
1091
+ #
1092
+ # @!macro promises.param.executor
1093
+ # @!macro promises.param.args
1094
+ # @!macro promise.param.callback
1095
+ # @return [self]
1096
+ # @yield [value, *args] to the callback.
1097
+ def on_fulfillment_using(executor, *args, &callback)
1098
+ add_callback :async_callback_on_fulfillment, executor, args, callback
1099
+ end
1100
+
1101
+ # @!macro promises.shortcut.using
1102
+ # @return [self]
1103
+ def on_rejection(*args, &callback)
1104
+ on_rejection_using @DefaultExecutor, *args, &callback
1105
+ end
1106
+
1107
+ # Stores the callback to be executed synchronously on resolving thread after it is
1108
+ # rejected. Does nothing on fulfillment.
1109
+ #
1110
+ # @!macro promises.param.args
1111
+ # @!macro promise.param.callback
1112
+ # @return [self]
1113
+ # @yield [reason, *args] to the callback.
1114
+ def on_rejection!(*args, &callback)
1115
+ add_callback :callback_on_rejection, args, callback
1116
+ end
1117
+
1118
+ # Stores the callback to be executed asynchronously on executor after it is
1119
+ # rejected. Does nothing on fulfillment.
1120
+ #
1121
+ # @!macro promises.param.executor
1122
+ # @!macro promises.param.args
1123
+ # @!macro promise.param.callback
1124
+ # @return [self]
1125
+ # @yield [reason, *args] to the callback.
1126
+ def on_rejection_using(executor, *args, &callback)
1127
+ add_callback :async_callback_on_rejection, executor, args, callback
1128
+ end
1129
+
1130
+ # Allows to use futures as green threads. The receiver has to evaluate to a future which
1131
+ # represents what should be done next. It basically flattens indefinitely until non Future
1132
+ # values is returned which becomes result of the returned future. Any encountered exception
1133
+ # will become reason of the returned future.
1134
+ #
1135
+ # @return [Future]
1136
+ # @example
1137
+ # body = lambda do |v|
1138
+ # v += 1
1139
+ # v < 5 ? Promises.future(v, &body) : v
1140
+ # end
1141
+ # Promises.future(0, &body).run.value! # => 5
1142
+ def run
1143
+ RunFuturePromise.new_blocked_by1(self, @DefaultExecutor).future
1144
+ end
1145
+
1146
+ # @!visibility private
1147
+ def apply(args, block)
1148
+ internal_state.apply args, block
1149
+ end
1150
+
1151
+ # Converts future to event which is resolved when future is resolved by fulfillment or rejection.
1152
+ #
1153
+ # @return [Event]
1154
+ def to_event
1155
+ event = Promises.resolvable_event
1156
+ ensure
1157
+ chain_resolvable(event)
1158
+ end
1159
+
1160
+ # Returns self, since this is a future
1161
+ # @return [Future]
1162
+ def to_future
1163
+ self
1164
+ end
1165
+
1166
+ private
1167
+
1168
+ def rejected_resolution(raise_on_reassign, state)
1169
+ if raise_on_reassign
1170
+ raise Concurrent::MultipleAssignmentError.new(
1171
+ "Future can be resolved only once. It's #{result}, trying to set #{state.result}.",
1172
+ current_result: result, new_result: state.result)
1173
+ end
1174
+ return false
1175
+ end
1176
+
1177
+ def wait_until_resolved!(timeout = nil)
1178
+ result = wait_until_resolved(timeout)
1179
+ raise self if rejected?
1180
+ result
1181
+ end
1182
+
1183
+ def async_callback_on_fulfillment(state, executor, args, callback)
1184
+ with_async(executor, state, args, callback) do |st, ar, cb|
1185
+ callback_on_fulfillment st, ar, cb
1186
+ end
1187
+ end
1188
+
1189
+ def async_callback_on_rejection(state, executor, args, callback)
1190
+ with_async(executor, state, args, callback) do |st, ar, cb|
1191
+ callback_on_rejection st, ar, cb
1192
+ end
1193
+ end
1194
+
1195
+ def callback_on_fulfillment(state, args, callback)
1196
+ state.apply args, callback if state.fulfilled?
1197
+ end
1198
+
1199
+ def callback_on_rejection(state, args, callback)
1200
+ state.apply args, callback unless state.fulfilled?
1201
+ end
1202
+
1203
+ def callback_on_resolution(state, args, callback)
1204
+ callback.call(*state.result, *args)
1205
+ end
1206
+
1207
+ end
1208
+
1209
+ # Marker module of Future, Event resolved manually by user.
1210
+ module Resolvable
1211
+ end
1212
+
1213
+ # A Event which can be resolved by user.
1214
+ class ResolvableEvent < Event
1215
+ include Resolvable
1216
+
1217
+
1218
+ # @!macro raise_on_reassign
1219
+ # @raise [MultipleAssignmentError] when already resolved and raise_on_reassign is true.
1220
+
1221
+ # @!macro promise.param.raise_on_reassign
1222
+ # @param [Boolean] raise_on_reassign should method raise exception if already resolved
1223
+ # @return [self, false] false is returner when raise_on_reassign is false and the receiver
1224
+ # is already resolved.
1225
+ #
1226
+
1227
+ # Makes the event resolved, which triggers all dependent futures.
1228
+ #
1229
+ # @!macro promise.param.raise_on_reassign
1230
+ def resolve(raise_on_reassign = true)
1231
+ resolve_with RESOLVED, raise_on_reassign
1232
+ end
1233
+
1234
+ # Creates new event wrapping receiver, effectively hiding the resolve method.
1235
+ #
1236
+ # @return [Event]
1237
+ def with_hidden_resolvable
1238
+ @with_hidden_resolvable ||= EventWrapperPromise.new_blocked_by1(self, @DefaultExecutor).event
1239
+ end
1240
+ end
1241
+
1242
+ # A Future which can be resolved by user.
1243
+ class ResolvableFuture < Future
1244
+ include Resolvable
1245
+
1246
+ # Makes the future resolved with result of triplet `fulfilled?`, `value`, `reason`,
1247
+ # which triggers all dependent futures.
1248
+ #
1249
+ # @!macro promise.param.raise_on_reassign
1250
+ def resolve(fulfilled = true, value = nil, reason = nil, raise_on_reassign = true)
1251
+ resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason), raise_on_reassign)
1252
+ end
1253
+
1254
+ # Makes the future fulfilled with `value`,
1255
+ # which triggers all dependent futures.
1256
+ #
1257
+ # @!macro promise.param.raise_on_reassign
1258
+ def fulfill(value, raise_on_reassign = true)
1259
+ promise.fulfill(value, raise_on_reassign)
1260
+ end
1261
+
1262
+ # Makes the future rejected with `reason`,
1263
+ # which triggers all dependent futures.
1264
+ #
1265
+ # @!macro promise.param.raise_on_reassign
1266
+ def reject(reason, raise_on_reassign = true)
1267
+ promise.reject(reason, raise_on_reassign)
1268
+ end
1269
+
1270
+ # Evaluates the block and sets its result as future's value fulfilling, if the block raises
1271
+ # an exception the future rejects with it.
1272
+ # @yield [*args] to the block.
1273
+ # @yieldreturn [Object] value
1274
+ # @return [self]
1275
+ def evaluate_to(*args, &block)
1276
+ promise.evaluate_to(*args, block)
1277
+ end
1278
+
1279
+ # Evaluates the block and sets its result as future's value fulfilling, if the block raises
1280
+ # an exception the future rejects with it.
1281
+ # @yield [*args] to the block.
1282
+ # @yieldreturn [Object] value
1283
+ # @return [self]
1284
+ # @raise [Exception] also raise reason on rejection.
1285
+ def evaluate_to!(*args, &block)
1286
+ promise.evaluate_to(*args, block).wait!
1287
+ end
1288
+
1289
+ # Creates new future wrapping receiver, effectively hiding the resolve method and similar.
1290
+ #
1291
+ # @return [Future]
1292
+ def with_hidden_resolvable
1293
+ @with_hidden_resolvable ||= FutureWrapperPromise.new_blocked_by1(self, @DefaultExecutor).future
1294
+ end
1295
+ end
1296
+
1297
+ # @abstract
1298
+ # @private
1299
+ class AbstractPromise < Synchronization::Object
1300
+ safe_initialization!
1301
+ include InternalStates
1302
+
1303
+ def initialize(future)
1304
+ super()
1305
+ @Future = future
1306
+ end
1307
+
1308
+ def future
1309
+ @Future
1310
+ end
1311
+
1312
+ alias_method :event, :future
1313
+
1314
+ def default_executor
1315
+ future.default_executor
1316
+ end
1317
+
1318
+ def state
1319
+ future.state
1320
+ end
1321
+
1322
+ def touch
1323
+ end
1324
+
1325
+ def to_s
1326
+ format '%s %s>', super[0..-2], @Future
1327
+ end
1328
+
1329
+ alias_method :inspect, :to_s
1330
+
1331
+ def delayed_because
1332
+ nil
1333
+ end
1334
+
1335
+ private
1336
+
1337
+ def resolve_with(new_state, raise_on_reassign = true)
1338
+ @Future.resolve_with(new_state, raise_on_reassign)
1339
+ end
1340
+
1341
+ # @return [Future]
1342
+ def evaluate_to(*args, block)
1343
+ resolve_with Fulfilled.new(block.call(*args))
1344
+ rescue Exception => error
1345
+ resolve_with Rejected.new(error)
1346
+ raise error unless error.is_a?(StandardError)
1347
+ end
1348
+ end
1349
+
1350
+ class ResolvableEventPromise < AbstractPromise
1351
+ def initialize(default_executor)
1352
+ super ResolvableEvent.new(self, default_executor)
1353
+ end
1354
+ end
1355
+
1356
+ class ResolvableFuturePromise < AbstractPromise
1357
+ def initialize(default_executor)
1358
+ super ResolvableFuture.new(self, default_executor)
1359
+ end
1360
+
1361
+ def fulfill(value, raise_on_reassign)
1362
+ resolve_with Fulfilled.new(value), raise_on_reassign
1363
+ end
1364
+
1365
+ def reject(reason, raise_on_reassign)
1366
+ resolve_with Rejected.new(reason), raise_on_reassign
1367
+ end
1368
+
1369
+ public :evaluate_to
1370
+ end
1371
+
1372
+ # @abstract
1373
+ class InnerPromise < AbstractPromise
1374
+ end
1375
+
1376
+ # @abstract
1377
+ class BlockedPromise < InnerPromise
1378
+
1379
+ private_class_method :new
1380
+
1381
+ def self.new_blocked_by1(blocker, *args, &block)
1382
+ blocker_delayed = blocker.promise.delayed_because
1383
+ promise = new(blocker_delayed, 1, *args, &block)
1384
+ blocker.add_callback_notify_blocked promise, 0
1385
+ promise
1386
+ end
1387
+
1388
+ def self.new_blocked_by2(blocker1, blocker2, *args, &block)
1389
+ blocker_delayed1 = blocker1.promise.delayed_because
1390
+ blocker_delayed2 = blocker2.promise.delayed_because
1391
+ delayed = if blocker_delayed1 && blocker_delayed2
1392
+ # TODO (pitr-ch 23-Dec-2016): use arrays when we know it will not grow (only flat adds delay)
1393
+ LockFreeStack.of2(blocker_delayed1, blocker_delayed2)
1394
+ else
1395
+ blocker_delayed1 || blocker_delayed2
1396
+ end
1397
+ promise = new(delayed, 2, *args, &block)
1398
+ blocker1.add_callback_notify_blocked promise, 0
1399
+ blocker2.add_callback_notify_blocked promise, 1
1400
+ promise
1401
+ end
1402
+
1403
+ def self.new_blocked_by(blockers, *args, &block)
1404
+ delayed = blockers.reduce(nil) { |d, f| add_delayed d, f.promise.delayed_because }
1405
+ promise = new(delayed, blockers.size, *args, &block)
1406
+ blockers.each_with_index { |f, i| f.add_callback_notify_blocked promise, i }
1407
+ promise
1408
+ end
1409
+
1410
+ def self.add_delayed(delayed1, delayed2)
1411
+ if delayed1 && delayed2
1412
+ delayed1.push delayed2
1413
+ delayed1
1414
+ else
1415
+ delayed1 || delayed2
1416
+ end
1417
+ end
1418
+
1419
+ def initialize(delayed, blockers_count, future)
1420
+ super(future)
1421
+ @Delayed = delayed
1422
+ @Countdown = AtomicFixnum.new blockers_count
1423
+ end
1424
+
1425
+ def on_blocker_resolution(future, index)
1426
+ countdown = process_on_blocker_resolution(future, index)
1427
+ resolvable = resolvable?(countdown, future, index)
1428
+
1429
+ on_resolvable(future, index) if resolvable
1430
+ end
1431
+
1432
+ def delayed_because
1433
+ @Delayed
1434
+ end
1435
+
1436
+ def touch
1437
+ clear_and_propagate_touch
1438
+ end
1439
+
1440
+ # for inspection only
1441
+ def blocked_by
1442
+ blocked_by = []
1443
+ ObjectSpace.each_object(AbstractEventFuture) { |o| blocked_by.push o if o.blocks.include? self }
1444
+ blocked_by
1445
+ end
1446
+
1447
+ private
1448
+
1449
+ def clear_and_propagate_touch(stack_or_element = @Delayed)
1450
+ return if stack_or_element.nil?
1451
+
1452
+ if stack_or_element.is_a? LockFreeStack
1453
+ stack_or_element.clear_each { |element| clear_and_propagate_touch element }
1454
+ else
1455
+ stack_or_element.touch unless stack_or_element.nil? # if still present
1456
+ end
1457
+ end
1458
+
1459
+ # @return [true,false] if resolvable
1460
+ def resolvable?(countdown, future, index)
1461
+ countdown.zero?
1462
+ end
1463
+
1464
+ def process_on_blocker_resolution(future, index)
1465
+ @Countdown.decrement
1466
+ end
1467
+
1468
+ def on_resolvable(resolved_future, index)
1469
+ raise NotImplementedError
1470
+ end
1471
+ end
1472
+
1473
+ # @abstract
1474
+ class BlockedTaskPromise < BlockedPromise
1475
+ def initialize(delayed, blockers_count, default_executor, executor, args, &task)
1476
+ raise ArgumentError, 'no block given' unless block_given?
1477
+ super delayed, 1, Future.new(self, default_executor)
1478
+ @Executor = executor
1479
+ @Task = task
1480
+ @Args = args
1481
+ end
1482
+
1483
+ def executor
1484
+ @Executor
1485
+ end
1486
+ end
1487
+
1488
+ class ThenPromise < BlockedTaskPromise
1489
+ private
1490
+
1491
+ def initialize(delayed, blockers_count, default_executor, executor, args, &task)
1492
+ super delayed, blockers_count, default_executor, executor, args, &task
1493
+ end
1494
+
1495
+ def on_resolvable(resolved_future, index)
1496
+ if resolved_future.fulfilled?
1497
+ Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task|
1498
+ evaluate_to lambda { future.apply args, task }
1499
+ end
1500
+ else
1501
+ resolve_with resolved_future.internal_state
1502
+ end
1503
+ end
1504
+ end
1505
+
1506
+ class RescuePromise < BlockedTaskPromise
1507
+ private
1508
+
1509
+ def initialize(delayed, blockers_count, default_executor, executor, args, &task)
1510
+ super delayed, blockers_count, default_executor, executor, args, &task
1511
+ end
1512
+
1513
+ def on_resolvable(resolved_future, index)
1514
+ if resolved_future.rejected?
1515
+ Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task|
1516
+ evaluate_to lambda { future.apply args, task }
1517
+ end
1518
+ else
1519
+ resolve_with resolved_future.internal_state
1520
+ end
1521
+ end
1522
+ end
1523
+
1524
+ class ChainPromise < BlockedTaskPromise
1525
+ private
1526
+
1527
+ def on_resolvable(resolved_future, index)
1528
+ if Future === resolved_future
1529
+ Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task|
1530
+ evaluate_to(*future.result, *args, task)
1531
+ end
1532
+ else
1533
+ Concurrent.executor(@Executor).post(@Args, @Task) do |args, task|
1534
+ evaluate_to(*args, task)
1535
+ end
1536
+ end
1537
+ end
1538
+ end
1539
+
1540
+ # will be immediately resolved
1541
+ class ImmediateEventPromise < InnerPromise
1542
+ def initialize(default_executor)
1543
+ super Event.new(self, default_executor).resolve_with(RESOLVED)
1544
+ end
1545
+ end
1546
+
1547
+ class ImmediateFuturePromise < InnerPromise
1548
+ def initialize(default_executor, fulfilled, value, reason)
1549
+ super Future.new(self, default_executor).
1550
+ resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason))
1551
+ end
1552
+ end
1553
+
1554
+ class AbstractFlatPromise < BlockedPromise
1555
+
1556
+ def initialize(delayed_because, blockers_count, event_or_future)
1557
+ delayed = LockFreeStack.of1(self)
1558
+ super(delayed, blockers_count, event_or_future)
1559
+ # noinspection RubyArgCount
1560
+ @Touched = AtomicBoolean.new false
1561
+ @DelayedBecause = delayed_because || LockFreeStack.new
1562
+
1563
+ event_or_future.add_callback_clear_delayed_node delayed.peek
1564
+ end
1565
+
1566
+ def touch
1567
+ if @Touched.make_true
1568
+ clear_and_propagate_touch @DelayedBecause
1569
+ end
1570
+ end
1571
+
1572
+ private
1573
+
1574
+ def touched?
1575
+ @Touched.value
1576
+ end
1577
+
1578
+ def on_resolvable(resolved_future, index)
1579
+ resolve_with resolved_future.internal_state
1580
+ end
1581
+
1582
+ def resolvable?(countdown, future, index)
1583
+ !@Future.internal_state.resolved? && super(countdown, future, index)
1584
+ end
1585
+
1586
+ def add_delayed_of(future)
1587
+ delayed = future.promise.delayed_because
1588
+ if touched?
1589
+ clear_and_propagate_touch delayed
1590
+ else
1591
+ BlockedPromise.add_delayed @DelayedBecause, delayed
1592
+ clear_and_propagate_touch @DelayedBecause if touched?
1593
+ end
1594
+ end
1595
+
1596
+ end
1597
+
1598
+ class FlatEventPromise < AbstractFlatPromise
1599
+
1600
+ private
1601
+
1602
+ def initialize(delayed, blockers_count, default_executor)
1603
+ super delayed, 2, Event.new(self, default_executor)
1604
+ end
1605
+
1606
+ def process_on_blocker_resolution(future, index)
1607
+ countdown = super(future, index)
1608
+ if countdown.nonzero?
1609
+ internal_state = future.internal_state
1610
+
1611
+ unless internal_state.fulfilled?
1612
+ resolve_with RESOLVED
1613
+ return countdown
1614
+ end
1615
+
1616
+ value = internal_state.value
1617
+ case value
1618
+ when Future, Event
1619
+ add_delayed_of value
1620
+ value.add_callback_notify_blocked self, nil
1621
+ countdown
1622
+ else
1623
+ resolve_with RESOLVED
1624
+ end
1625
+ end
1626
+ countdown
1627
+ end
1628
+
1629
+ end
1630
+
1631
+ class FlatFuturePromise < AbstractFlatPromise
1632
+
1633
+ private
1634
+
1635
+ def initialize(delayed, blockers_count, levels, default_executor)
1636
+ raise ArgumentError, 'levels has to be higher than 0' if levels < 1
1637
+ # flat promise may result to a future having delayed futures, therefore we have to have empty stack
1638
+ # to be able to add new delayed futures
1639
+ super delayed || LockFreeStack.new, 1 + levels, Future.new(self, default_executor)
1640
+ end
1641
+
1642
+ def process_on_blocker_resolution(future, index)
1643
+ countdown = super(future, index)
1644
+ if countdown.nonzero?
1645
+ internal_state = future.internal_state
1646
+
1647
+ unless internal_state.fulfilled?
1648
+ resolve_with internal_state
1649
+ return countdown
1650
+ end
1651
+
1652
+ value = internal_state.value
1653
+ case value
1654
+ when Future
1655
+ add_delayed_of value
1656
+ value.add_callback_notify_blocked self, nil
1657
+ countdown
1658
+ when Event
1659
+ evaluate_to(lambda { raise TypeError, 'cannot flatten to Event' })
1660
+ else
1661
+ evaluate_to(lambda { raise TypeError, "returned value #{value.inspect} is not a Future" })
1662
+ end
1663
+ end
1664
+ countdown
1665
+ end
1666
+
1667
+ end
1668
+
1669
+ class RunFuturePromise < AbstractFlatPromise
1670
+
1671
+ private
1672
+
1673
+ def initialize(delayed, blockers_count, default_executor)
1674
+ super delayed, 1, Future.new(self, default_executor)
1675
+ end
1676
+
1677
+ def process_on_blocker_resolution(future, index)
1678
+ internal_state = future.internal_state
1679
+
1680
+ unless internal_state.fulfilled?
1681
+ resolve_with internal_state
1682
+ return 0
1683
+ end
1684
+
1685
+ value = internal_state.value
1686
+ case value
1687
+ when Future
1688
+ add_delayed_of value
1689
+ value.add_callback_notify_blocked self, nil
1690
+ else
1691
+ resolve_with internal_state
1692
+ end
1693
+
1694
+ 1
1695
+ end
1696
+ end
1697
+
1698
+ class ZipEventEventPromise < BlockedPromise
1699
+ def initialize(delayed, blockers_count, default_executor)
1700
+ super delayed, 2, Event.new(self, default_executor)
1701
+ end
1702
+
1703
+ private
1704
+
1705
+ def on_resolvable(resolved_future, index)
1706
+ resolve_with RESOLVED
1707
+ end
1708
+ end
1709
+
1710
+ class ZipFutureEventPromise < BlockedPromise
1711
+ def initialize(delayed, blockers_count, default_executor)
1712
+ super delayed, 2, Future.new(self, default_executor)
1713
+ @result = nil
1714
+ end
1715
+
1716
+ private
1717
+
1718
+ def process_on_blocker_resolution(future, index)
1719
+ # first blocking is future, take its result
1720
+ @result = future.internal_state if index == 0
1721
+ # super has to be called after above to piggyback on volatile @Countdown
1722
+ super future, index
1723
+ end
1724
+
1725
+ def on_resolvable(resolved_future, index)
1726
+ resolve_with @result
1727
+ end
1728
+ end
1729
+
1730
+ class EventWrapperPromise < BlockedPromise
1731
+ def initialize(delayed, blockers_count, default_executor)
1732
+ super delayed, 1, Event.new(self, default_executor)
1733
+ end
1734
+
1735
+ private
1736
+
1737
+ def on_resolvable(resolved_future, index)
1738
+ resolve_with RESOLVED
1739
+ end
1740
+ end
1741
+
1742
+ class FutureWrapperPromise < BlockedPromise
1743
+ def initialize(delayed, blockers_count, default_executor)
1744
+ super delayed, 1, Future.new(self, default_executor)
1745
+ end
1746
+
1747
+ private
1748
+
1749
+ def on_resolvable(resolved_future, index)
1750
+ resolve_with resolved_future.internal_state
1751
+ end
1752
+ end
1753
+
1754
+ class ZipFuturesPromise < BlockedPromise
1755
+
1756
+ private
1757
+
1758
+ def initialize(delayed, blockers_count, default_executor)
1759
+ super(delayed, blockers_count, Future.new(self, default_executor))
1760
+ @Resolutions = ::Array.new(blockers_count, nil)
1761
+
1762
+ on_resolvable nil, nil if blockers_count == 0
1763
+ end
1764
+
1765
+ def process_on_blocker_resolution(future, index)
1766
+ # TODO (pitr-ch 18-Dec-2016): Can we assume that array will never break under parallel access when never re-sized?
1767
+ @Resolutions[index] = future.internal_state # has to be set before countdown in super
1768
+ super future, index
1769
+ end
1770
+
1771
+ def on_resolvable(resolved_future, index)
1772
+ all_fulfilled = true
1773
+ values = ::Array.new(@Resolutions.size)
1774
+ reasons = ::Array.new(@Resolutions.size)
1775
+
1776
+ @Resolutions.each_with_index do |internal_state, i|
1777
+ fulfilled, values[i], reasons[i] = internal_state.result
1778
+ all_fulfilled &&= fulfilled
1779
+ end
1780
+
1781
+ if all_fulfilled
1782
+ resolve_with FulfilledArray.new(values)
1783
+ else
1784
+ resolve_with PartiallyRejected.new(values, reasons)
1785
+ end
1786
+ end
1787
+ end
1788
+
1789
+ class ZipEventsPromise < BlockedPromise
1790
+
1791
+ private
1792
+
1793
+ def initialize(delayed, blockers_count, default_executor)
1794
+ super delayed, blockers_count, Event.new(self, default_executor)
1795
+
1796
+ on_resolvable nil, nil if blockers_count == 0
1797
+ end
1798
+
1799
+ def on_resolvable(resolved_future, index)
1800
+ resolve_with RESOLVED
1801
+ end
1802
+ end
1803
+
1804
+ # @abstract
1805
+ class AbstractAnyPromise < BlockedPromise
1806
+ end
1807
+
1808
+ class AnyResolvedFuturePromise < AbstractAnyPromise
1809
+
1810
+ private
1811
+
1812
+ def initialize(delayed, blockers_count, default_executor)
1813
+ super delayed, blockers_count, Future.new(self, default_executor)
1814
+ end
1815
+
1816
+ def resolvable?(countdown, future, index)
1817
+ true
1818
+ end
1819
+
1820
+ def on_resolvable(resolved_future, index)
1821
+ resolve_with resolved_future.internal_state, false
1822
+ end
1823
+ end
1824
+
1825
+ class AnyResolvedEventPromise < AbstractAnyPromise
1826
+
1827
+ private
1828
+
1829
+ def initialize(delayed, blockers_count, default_executor)
1830
+ super delayed, blockers_count, Event.new(self, default_executor)
1831
+ end
1832
+
1833
+ def resolvable?(countdown, future, index)
1834
+ true
1835
+ end
1836
+
1837
+ def on_resolvable(resolved_future, index)
1838
+ resolve_with RESOLVED, false
1839
+ end
1840
+ end
1841
+
1842
+ class AnyFulfilledFuturePromise < AnyResolvedFuturePromise
1843
+
1844
+ private
1845
+
1846
+ def resolvable?(countdown, future, index)
1847
+ future.fulfilled? ||
1848
+ # inlined super from BlockedPromise
1849
+ countdown.zero?
1850
+ end
1851
+ end
1852
+
1853
+ class DelayPromise < InnerPromise
1854
+
1855
+ def initialize(default_executor)
1856
+ event = Event.new(self, default_executor)
1857
+ @Delayed = LockFreeStack.of1(self)
1858
+ super event
1859
+ event.add_callback_clear_delayed_node @Delayed.peek
1860
+ end
1861
+
1862
+ def touch
1863
+ @Future.resolve_with RESOLVED
1864
+ end
1865
+
1866
+ def delayed_because
1867
+ @Delayed
1868
+ end
1869
+
1870
+ end
1871
+
1872
+ class ScheduledPromise < InnerPromise
1873
+ def intended_time
1874
+ @IntendedTime
1875
+ end
1876
+
1877
+ def inspect
1878
+ "#{to_s[0..-2]} intended_time: #{@IntendedTime}>"
1879
+ end
1880
+
1881
+ private
1882
+
1883
+ def initialize(default_executor, intended_time)
1884
+ super Event.new(self, default_executor)
1885
+
1886
+ @IntendedTime = intended_time
1887
+
1888
+ in_seconds = begin
1889
+ now = Time.now
1890
+ schedule_time = if @IntendedTime.is_a? Time
1891
+ @IntendedTime
1892
+ else
1893
+ now + @IntendedTime
1894
+ end
1895
+ [0, schedule_time.to_f - now.to_f].max
1896
+ end
1897
+
1898
+ Concurrent.global_timer_set.post(in_seconds) do
1899
+ @Future.resolve_with RESOLVED
1900
+ end
1901
+ end
1902
+ end
1903
+
1904
+ extend FactoryMethods
1905
+
1906
+ private_constant :AbstractPromise,
1907
+ :ResolvableEventPromise,
1908
+ :ResolvableFuturePromise,
1909
+ :InnerPromise,
1910
+ :BlockedPromise,
1911
+ :BlockedTaskPromise,
1912
+ :ThenPromise,
1913
+ :RescuePromise,
1914
+ :ChainPromise,
1915
+ :ImmediateEventPromise,
1916
+ :ImmediateFuturePromise,
1917
+ :AbstractFlatPromise,
1918
+ :FlatFuturePromise,
1919
+ :FlatEventPromise,
1920
+ :RunFuturePromise,
1921
+ :ZipEventEventPromise,
1922
+ :ZipFutureEventPromise,
1923
+ :EventWrapperPromise,
1924
+ :FutureWrapperPromise,
1925
+ :ZipFuturesPromise,
1926
+ :ZipEventsPromise,
1927
+ :AbstractAnyPromise,
1928
+ :AnyResolvedFuturePromise,
1929
+ :AnyFulfilledFuturePromise,
1930
+ :AnyResolvedEventPromise,
1931
+ :DelayPromise,
1932
+ :ScheduledPromise
1933
+
1934
+
1935
+ end
1936
+ end