concurrent-ruby-edge 0.2.4 → 0.3.0

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