core-async 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1475f225e7a3c63b06f254003ff34f377ab467aa26bb086903ba85db0c16d6ec
4
- data.tar.gz: 013b3220d6e1d6b051524c57e551880a064aad3dcace1c40110f60793c18c9a1
3
+ metadata.gz: ad38e4e865f4be308699dde8ff3bfe22cf4873a7de3b2841d235d8a02c6a33f7
4
+ data.tar.gz: 04b405d8f2dbc07fcba33cb76871748165ac1b01c1337e21ea19e2dc225170af
5
5
  SHA512:
6
- metadata.gz: 2b7a37821649338dd1336d587e3c49d1df817729470c01c98cbbeb77c50e07ee7163aead7eabb5ef37bf288f0a00589d705933f16c1114656ebd023deb81e24b
7
- data.tar.gz: f71a80e8efe333555b5d436e8f2d0cde7450754059bbf70d2266507b0bed1c6fb505c1c3a09ef29cf748566ef9d6100d0efea92a4e3f578a502205b3a2e6fdf7
6
+ metadata.gz: e97c567a1f930b83302321229038a8cddb4c1be04dacc7986c78f8def3792adfc4e9b65e398dfc48ca482e4fb710de2189f9a09aec7e433495c5f8089ae9ecd5
7
+ data.tar.gz: 6fa8167bf7345e5b3d61f55a47938bc81cd84fa5c59156c0bd4c99456b632942c7b95f549add6ae9905da155479fb6950841f2a53170ce688b6b10fa69f3f9ed
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [v0.9.0](https://github.com/metabahn/corerb/releases/tag/2021-10-24)
2
+
3
+ *released on 2021-10-24*
4
+
5
+ * `chg` [#82](https://github.com/metabahn/corerb/pull/82) Refactor to use a new fiber scheduler ([bryanp](https://github.com/bryanp))
6
+
1
7
  ## [v0.8.0](https://github.com/metabahn/corerb/releases/tag/2021-07-15)
2
8
 
3
9
  *released on 2021-07-15*
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "async"
3
+ require_relative "scheduler"
4
4
 
5
- # Turn the console logger off everywhere.
5
+ # Define a top-level scheduler.
6
6
  #
7
- ENV["CONSOLE_LEVEL"] ||= "5"
7
+ scheduler = Core::Async::Scheduler.new
8
+ Fiber.set_scheduler(scheduler)
9
+
10
+ # Automatically run the top-level scheduler at exit, blocking until all fibers are complete.
11
+ #
12
+ at_exit { scheduler.run }
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "is/inspectable"
4
+
5
+ module Core
6
+ module Async
7
+ # [public] Raised when the fiber is canceled.
8
+ #
9
+ class Cancel < RuntimeError
10
+ include Is::Inspectable
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "is/inspectable"
4
+
5
+ module Core
6
+ module Async
7
+ # [public] Channels let fibers wait on future published values.
8
+ #
9
+ class Channel
10
+ include Is::Inspectable
11
+ inspects without: [:@subscribers]
12
+
13
+ def initialize
14
+ @subscribers = []
15
+ end
16
+
17
+ # [public] Subscribe the current fiber, blocking until a value is published.
18
+ #
19
+ def subscribe
20
+ @subscribers << Fiber.current
21
+ Fiber.scheduler.transfer
22
+ end
23
+
24
+ # [public] Publish the given value to all subscribers.
25
+ #
26
+ def publish(value = nil)
27
+ subscribers = @subscribers
28
+ @subscribers = []
29
+
30
+ while (fiber = subscribers.shift)
31
+ if fiber.alive?
32
+ Fiber.scheduler.resume(fiber, value)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -13,13 +13,13 @@ module Core
13
13
  # [public] Builds a collection from an enumerable object.
14
14
  #
15
15
  def build(object)
16
- aware do
17
- errored, stopped = false
16
+ errored = false
17
+ stopped = false
18
+ values = []
18
19
 
19
- values = object.map { |value|
20
- break if errored || stopped
21
-
22
- async do
20
+ object.each do |value|
21
+ future = async {
22
+ begin
23
23
  if block_given?
24
24
  yield value
25
25
  else
@@ -33,8 +33,16 @@ module Core
33
33
  end
34
34
  }
35
35
 
36
- new(values) if values
36
+ unless stopped
37
+ values << future
38
+ end
39
+
40
+ if errored || stopped
41
+ break
42
+ end
37
43
  end
44
+
45
+ new(values)
38
46
  end
39
47
  end
40
48
 
@@ -26,22 +26,24 @@ module Core
26
26
  return to_enum(:each)
27
27
  end
28
28
 
29
- await do
30
- errored, stopped = false
31
-
32
- @object.each do |value|
33
- break if errored || stopped
34
-
35
- async do
36
- yield value
37
- rescue LocalJumpError
38
- stopped = true
39
- rescue => error
40
- errored = true
41
- raise error
42
- end
29
+ errored = false
30
+ stopped = false
31
+ futures = []
32
+
33
+ @object.each do |value|
34
+ break if errored || stopped
35
+
36
+ futures << async do
37
+ yield value
38
+ rescue LocalJumpError
39
+ stopped = true
40
+ rescue => error
41
+ errored = true
42
+ raise error
43
43
  end
44
44
  end
45
+
46
+ futures.each(&:wait)
45
47
  end
46
48
  end
47
49
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "is/inspectable"
4
+
5
+ module Core
6
+ module Async
7
+ # [public] Raised internally to communicate a fiber error.
8
+ #
9
+ class Failure
10
+ include Is::Inspectable
11
+
12
+ def initialize(error)
13
+ @error = error
14
+ end
15
+
16
+ # [public] The original error.
17
+ #
18
+ attr_reader :error
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "is/inspectable"
4
+
5
+ require_relative "channel"
6
+
7
+ module Core
8
+ module Async
9
+ # Internal object that wraps a fiber.
10
+ #
11
+ class Filament
12
+ include Is::Inspectable
13
+ inspects without: [:@object, :@channel, :@children, :@resolved]
14
+
15
+ def initialize
16
+ @object = nil
17
+ @channel = nil
18
+ @children = nil
19
+ @resolved = false
20
+ @value = nil
21
+ end
22
+
23
+ attr_accessor :object
24
+ attr_reader :children
25
+
26
+ def add_child(fiber)
27
+ (@children ||= []) << fiber
28
+ end
29
+
30
+ def resolve(value = nil)
31
+ unless @resolved
32
+ @value = value
33
+ @resolved = true
34
+ @channel&.publish(value)
35
+ end
36
+ end
37
+
38
+ def wait
39
+ if @resolved == false && @object&.alive?
40
+ (@channel ||= Channel.new).subscribe
41
+ else
42
+ @value
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -2,55 +2,132 @@
2
2
 
3
3
  require "is/inspectable"
4
4
 
5
+ require_relative "cancel"
6
+ require_relative "failure"
7
+ require_relative "scheduler"
8
+
5
9
  module Core
6
10
  module Async
7
11
  # [public] Represents a future result.
8
12
  #
9
13
  class Future
10
14
  include Is::Inspectable
11
- inspects without: [:@task]
15
+ inspects without: [:@fiber, :@raised, :@scheduler, :@filament]
12
16
 
13
- def initialize(task)
14
- @task = task
17
+ def initialize(&block)
15
18
  @error = nil
19
+ @result = nil
20
+ @status = :pending
21
+ @raised = false
22
+ @fiber = Fiber.schedule { |filament|
23
+ begin
24
+ @filament = filament
25
+ value = block.call
26
+ @result = resolve_value(value)
27
+ @status = :complete
28
+ @result
29
+ rescue Cancel
30
+ @status = :canceled
31
+ nil
32
+ rescue => error
33
+ @error = error
34
+ @status = :failed
35
+ raise error
36
+ end
37
+ }
16
38
  end
17
39
 
18
- # [public] Wait on the future to resolve, returning self.
40
+ # [public] The current status; one of :pending, :failed, :canceled, or :complete.
41
+ #
42
+ attr_reader :status
43
+
44
+ # [public] Wait on the future to resolve (including children), returning self.
19
45
  #
20
46
  def wait
21
- unless @error
22
- resolve
23
- end
47
+ resolve
24
48
 
25
49
  self
26
50
  end
27
51
 
28
- # [public] Attempt to cancel the future, returns true if successful.
52
+ # [public] Attempt to cancel the future, returning true if successful.
29
53
  #
30
54
  def cancel
31
55
  if pending?
32
- @task.stop
56
+ Fiber.scheduler.cancel(@fiber)
33
57
  end
34
58
 
35
59
  self
36
60
  end
37
61
 
38
- # [public] Return the result, blocking until available.
62
+ # [public] Wait until the result is available, returning the result. Only awaits explicitly awaited children.
39
63
  #
40
64
  def result
41
- @error || @result ||= resolve
42
- end
43
-
44
- private def resolve
45
- wait_all(@task)
65
+ resolve(false)
66
+ end
67
+
68
+ private def resolve(children = true)
69
+ case @status
70
+ when :pending
71
+ scheduler = Fiber.scheduler
72
+
73
+ result = catch :__corerb_async_future_failed do
74
+ if scheduler.running?
75
+ if children
76
+ resolve_all(@filament)
77
+ else
78
+ resolve_value(@filament.wait)
79
+ end
80
+ else
81
+ result = nil
82
+ finished = false
83
+
84
+ scheduler.fiber do
85
+ result = catch :__corerb_async_future_failed do
86
+ if children
87
+ resolve_all(@filament)
88
+ else
89
+ resolve_value(@filament.wait)
90
+ end
91
+ end
92
+
93
+ finished = true
94
+ end
95
+
96
+ scheduler.observe do
97
+ break if finished
98
+ end
99
+
100
+ resolve_value(result)
101
+ end
102
+ end
46
103
 
47
- resolve_value(@task.result)
104
+ case result
105
+ when Failure
106
+ @raised = true
107
+ raise result.error
108
+ else
109
+ result
110
+ end
111
+ when :failed
112
+ if @raised
113
+ @error
114
+ else
115
+ @raised = true
116
+ raise @error
117
+ end
118
+ else
119
+ @result
120
+ end
48
121
  rescue UncaughtThrowError => error
49
122
  throw error.tag, error.value
50
- rescue => error
51
- @error = error
123
+ end
124
+
125
+ private def resolve_all(filament)
126
+ filament.children&.each do |child|
127
+ resolve_all(child)
128
+ end
52
129
 
53
- raise error
130
+ resolve_value(filament.wait)
54
131
  end
55
132
 
56
133
  # [public] Return any error that occurred without re-raising, blocking until available.
@@ -66,60 +143,28 @@ module Core
66
143
  error
67
144
  end
68
145
 
69
- # [public] Return the status; one of :pending, :failed, or :complete.
70
- #
71
- def status
72
- if defined?(@status)
73
- @status
74
- else
75
- status = find_status
76
- if terminal_status?(status)
77
- @status = status
78
- end
79
-
80
- status
81
- end
82
- end
83
-
84
- private def find_status
85
- case @task.status
86
- when :running
87
- :pending
88
- when :stopped
89
- :canceled
90
- when :failed
91
- :failed
92
- when :complete
93
- :complete
94
- end
95
- end
96
-
97
- private def terminal_status?(status)
98
- status == :failed || status == :complete
99
- end
100
-
101
146
  # [public] Return `true` if pending.
102
147
  #
103
148
  def pending?
104
- status == :pending
149
+ @status == :pending
105
150
  end
106
151
 
107
152
  # [public] Return `true` if failed.
108
153
  #
109
154
  def failed?
110
- status == :failed
155
+ @status == :failed
111
156
  end
112
157
 
113
158
  # [public] Return `true` if canceled.
114
159
  #
115
160
  def canceled?
116
- status == :canceled
161
+ @status == :canceled
117
162
  end
118
163
 
119
164
  # [public] Return `true` if complete.
120
165
  #
121
166
  def complete?
122
- status == :complete
167
+ @status == :complete
123
168
  end
124
169
 
125
170
  # [public] Return `true` if failed or complete.
@@ -129,20 +174,15 @@ module Core
129
174
  end
130
175
 
131
176
  private def resolve_value(value)
132
- if value.is_a?(self.class)
177
+ case value
178
+ when self.class
133
179
  resolve_value(value.result)
180
+ when Failure
181
+ throw :__corerb_async_future_failed, value
134
182
  else
135
183
  value
136
184
  end
137
185
  end
138
-
139
- private def wait_all(task)
140
- task.children&.each do |child|
141
- wait_all(child)
142
- end
143
-
144
- task.wait
145
- end
146
186
  end
147
187
  end
148
188
  end
@@ -3,12 +3,13 @@
3
3
  require "is/inspectable"
4
4
 
5
5
  require_relative "../../is/async"
6
+ require_relative "scheduler"
6
7
 
7
8
  module Core
8
9
  module Async
9
- # [public] The top-level async context. Runs until all scheduled work is complete.
10
+ # [public] Creates a top-level async context that runs until all scheduled work is complete.
10
11
  #
11
- class Reactor
12
+ class Reactor < Scheduler
12
13
  include Is::Async
13
14
  include Is::Inspectable
14
15
  inspects without: [:@runnable]
@@ -18,37 +19,13 @@ module Core
18
19
  #
19
20
  def run(&block)
20
21
  instance = new
22
+ original_scheduler = Fiber.scheduler
23
+ Fiber.set_scheduler(instance)
21
24
  instance.run(&block)
25
+ ensure
26
+ Fiber.set_scheduler(original_scheduler)
22
27
  end
23
28
  end
24
-
25
- # [public] Run the reactor, yielding within the async context.
26
- #
27
- def run
28
- if (task = ::Async::Task.current?)
29
- reference = task.async { |child|
30
- @runnable = child
31
-
32
- yield self
33
- }
34
-
35
- wait_all(reference)
36
- else
37
- @runnable = ::Async::Reactor.new
38
-
39
- @runnable.run {
40
- async {
41
- yield self
42
- }.result
43
- }.wait
44
- end
45
- end
46
-
47
- # [public] Stop the reactor.
48
- #
49
- def stop
50
- @runnable&.stop
51
- end
52
29
  end
53
30
  end
54
31
  end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "event"
4
+ require "fiber"
5
+ require "timers/group"
6
+ require "is/inspectable"
7
+
8
+ require_relative "cancel"
9
+ require_relative "failure"
10
+ require_relative "filament"
11
+ require_relative "timeout"
12
+
13
+ module Core
14
+ module Async
15
+ # [public] The fiber scheduler.
16
+ #
17
+ class Scheduler
18
+ include Is::Inspectable
19
+ inspects without: [:@selector, :@timers, :@fibers]
20
+
21
+ extend Forwardable
22
+
23
+ # [public] Transfer from the current fiber to the selector.
24
+ #
25
+ def_delegator :@selector, :transfer
26
+
27
+ # [public] Yield the current fiber, resuming on the next tick.
28
+ #
29
+ def_delegator :@selector, :yield
30
+
31
+ # [public] Raise an error in the given fiber.
32
+ #
33
+ def_delegator :@selector, :raise
34
+
35
+ # [public] Resume the given fiber with the given value.
36
+ #
37
+ def_delegator :@selector, :resume
38
+
39
+ def initialize
40
+ @selector = Event::Selector.new(Fiber.current)
41
+ @timers = Timers::Group.new
42
+ @closed = false
43
+ @running = false
44
+ @fibers = {}
45
+ end
46
+
47
+ # [public] Run until there's no more work to do.
48
+ #
49
+ def run
50
+ @running = true
51
+
52
+ yield self if block_given?
53
+
54
+ result = nil
55
+ until result == :finished
56
+ result = tick
57
+ end
58
+ ensure
59
+ @running = false
60
+ end
61
+
62
+ # [public] Run until there's no more work to do, yielding before each tick.
63
+ #
64
+ def observe
65
+ @running = true
66
+
67
+ result = nil
68
+ until result == :finished
69
+ yield self
70
+ result = tick
71
+ end
72
+ ensure
73
+ @running = false
74
+ end
75
+
76
+ # [public] Returns `true` if the scheduler is running.
77
+ #
78
+ def running?
79
+ @running == true
80
+ end
81
+
82
+ # [public] Run one tick.
83
+ #
84
+ def tick
85
+ interval = @timers.wait_interval
86
+
87
+ if interval.nil?
88
+ if @fibers.empty?
89
+ return :finished
90
+ end
91
+ elsif interval < 0
92
+ interval = 0
93
+ end
94
+
95
+ @selector.select(interval)
96
+
97
+ @timers.fire
98
+ rescue Errno::EINTR
99
+ stop
100
+ end
101
+
102
+ # [public] Stop the scheduler, canceling each scheduled fiber.
103
+ #
104
+ def stop
105
+ signal = Cancel.new
106
+
107
+ @fibers.each_key do |fiber|
108
+ @selector.raise(fiber, signal)
109
+ end
110
+ end
111
+
112
+ # [public] Cancel the given fiber.
113
+ #
114
+ def cancel(fiber = Thread.current[:__corerb_async_current_fiber])
115
+ self.raise(fiber, Cancel) if fiber
116
+ end
117
+
118
+ # [public] Yields to the given block, timing out after the given seconds.
119
+ #
120
+ def timeout(seconds)
121
+ if seconds && seconds > 0
122
+ fiber = Fiber.current
123
+
124
+ timer = @timers.after(seconds) {
125
+ if fiber.alive?
126
+ fiber.raise(Timeout)
127
+ end
128
+ }
129
+ end
130
+
131
+ yield
132
+ ensure
133
+ timer&.cancel
134
+ end
135
+
136
+ #######################
137
+ ### Scheduler Interface
138
+ #######################
139
+
140
+ def block(blocker, timeout = nil)
141
+ if timeout
142
+ timer = create_timer(timeout)
143
+ end
144
+
145
+ @selector.transfer
146
+ ensure
147
+ timer&.cancel
148
+ end
149
+
150
+ def close
151
+ run
152
+ ensure
153
+ unless @closed
154
+ @closed = true
155
+
156
+ Fiber.set_scheduler(nil)
157
+ end
158
+ end
159
+
160
+ def fiber(&block)
161
+ filament = Filament.new
162
+
163
+ fiber = Fiber.new(blocking: false) {
164
+ begin
165
+ Thread.current[:__corerb_async_current_fiber] = filament
166
+ filament.object = fiber
167
+ result = block.call(filament)
168
+ rescue Cancel
169
+ result = nil
170
+ rescue => error
171
+ result = Failure.new(error)
172
+ ensure
173
+ @fibers.delete(fiber)
174
+ filament.resolve(result)
175
+ end
176
+ }
177
+
178
+ @fibers[fiber] = filament
179
+
180
+ if (parent = @fibers[Fiber.current])
181
+ parent.add_child(filament)
182
+ end
183
+
184
+ @selector.resume(fiber)
185
+
186
+ fiber
187
+ end
188
+
189
+ def io_wait(io, events, timeout = nil)
190
+ fiber = Fiber.current
191
+
192
+ if timeout
193
+ timer = @timers.after(timeout) {
194
+ fiber.raise(Timeout)
195
+ }
196
+ end
197
+
198
+ @selector.io_wait(fiber, io, events)
199
+ rescue Timeout
200
+ false
201
+ ensure
202
+ timer&.cancel
203
+ end
204
+
205
+ def kernel_sleep(duration = nil)
206
+ if duration
207
+ timer = create_timer(duration)
208
+ end
209
+
210
+ @selector.transfer
211
+ ensure
212
+ timer&.cancel
213
+ end
214
+
215
+ def process_wait(...)
216
+ @selector.process_wait(Fiber.current, ...)
217
+ end
218
+
219
+ def unblock(blocker, fiber)
220
+ @selector.push(fiber)
221
+ end
222
+
223
+ private def create_timer(duration)
224
+ fiber = Fiber.current
225
+
226
+ @timers.after(duration) {
227
+ if fiber.alive?
228
+ fiber.transfer(false)
229
+ end
230
+ }
231
+ end
232
+ end
233
+ end
234
+ end
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Core
4
4
  module Async
5
- VERSION = "0.8.0"
5
+ VERSION = "0.9.0"
6
6
 
7
+ # [public]
8
+ #
7
9
  def self.version
8
10
  VERSION
9
11
  end
@@ -13,15 +13,13 @@ module Core
13
13
  @target = target
14
14
  end
15
15
 
16
- def method_missing(name, *args, &block)
16
+ def method_missing(...)
17
17
  @target.async do
18
- @target.public_send(name, *args, &block)
18
+ @target.public_send(...)
19
19
  end
20
20
  end
21
21
 
22
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords)
23
-
24
- def respond_to_missing?(name, *)
22
+ def respond_to_missing?(...)
25
23
  true
26
24
  end
27
25
  end
data/lib/is/async.rb CHANGED
@@ -11,17 +11,9 @@ module Is
11
11
  module Async
12
12
  # [public] Call behavior asychronously, returning a future.
13
13
  #
14
- def async
15
- if block_given?
16
- task = ::Async::Reactor.run { |current|
17
- begin
18
- yield
19
- ensure
20
- current.yield
21
- end
22
- }
23
-
24
- Core::Async::Future.new(task)
14
+ def async(&block)
15
+ if block
16
+ Core::Async::Future.new(&block)
25
17
  else
26
18
  Core::Async::Wrapper.new(self)
27
19
  end
@@ -30,85 +22,31 @@ module Is
30
22
  # [public] Call behavior synchronously but within an async context, waiting on the result.
31
23
  #
32
24
  private def await
33
- if (task = ::Async::Task.current?)
34
- reference = task.async { |current|
35
- begin
36
- yield
37
- ensure
38
- current.yield
39
- end
40
- }
41
-
42
- wait_all(reference)
43
- else
44
- ::Async::Reactor.run { |task|
45
- async {
46
- yield
47
- }.result
48
- }.wait
49
- end
50
- rescue UncaughtThrowError => error
51
- throw error.tag, error.value
52
- end
53
-
54
- # [public] Call behavior within an async context without additional nesting.
55
- #
56
- private def aware
57
- if ::Async::Task.current?
25
+ async {
58
26
  yield
59
- else
60
- await do
61
- yield
62
- end
63
- end
64
- end
65
-
66
- # [public] Sleeps for `seconds` in a proper async context.
67
- #
68
- private def sleep(seconds)
69
- internal_await do |task|
70
- task.sleep(seconds)
71
- end
27
+ }.wait.result
72
28
  end
73
29
 
74
30
  # [public] Call asynchonous behavior in a proper async context, wrapped in a timeout.
75
31
  #
76
32
  # Raises `Core::Async::Timeout` if execution exceeds `seconds`.
77
33
  #
78
- private def timeout(seconds)
79
- internal_await do |task|
80
- timed_task = internal_async {
81
- yield
82
- }
83
-
84
- if seconds && seconds > 0
85
- task.with_timeout(seconds, Core::Async::Timeout) do
86
- timed_task.wait
87
- end
88
- else
89
- timed_task.wait
90
- end
91
- ensure
92
- timed_task&.stop
93
- end
94
- rescue UncaughtThrowError => error
95
- throw error.tag, error.value
34
+ private def timeout(seconds, &block)
35
+ async {
36
+ Fiber.scheduler.timeout(seconds, &block)
37
+ }.wait
96
38
  end
97
39
 
98
40
  # [public] Yields control to allow other fibers to execute.
99
41
  #
100
42
  private def defer
101
- if (task = ::Async::Task.current?)
102
- task.yield
103
- end
43
+ Fiber.scheduler.yield
104
44
  end
105
45
 
106
46
  # [public] Cancels the current async behavior if in progress.
107
47
  #
108
48
  private def cancel
109
- if (task = ::Async::Task.current?)
110
- task.stop
111
- end
49
+ Fiber.scheduler.cancel
112
50
  end
113
51
 
114
52
  # [public] Resolves a potential future to a final result.
@@ -116,38 +54,10 @@ module Is
116
54
  private def resolve(value)
117
55
  case value
118
56
  when Core::Async::Future
119
- value.result
57
+ resolve(value.result)
120
58
  else
121
59
  value
122
60
  end
123
61
  end
124
-
125
- private def internal_async
126
- ::Async::Reactor.run do |task|
127
- yield task
128
- end
129
- end
130
-
131
- private def internal_await
132
- if (task = ::Async::Task.current?)
133
- reference = task.async {
134
- yield task
135
- }
136
-
137
- wait_all(reference)
138
- else
139
- ::Async::Reactor.run { |task|
140
- yield task
141
- }.wait
142
- end
143
- end
144
-
145
- private def wait_all(task)
146
- task.children&.each do |child|
147
- wait_all(child)
148
- end
149
-
150
- task.wait
151
- end
152
62
  end
153
63
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: core-async
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Powell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-15 00:00:00.000000000 Z
11
+ date: 2021-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: async
14
+ name: event
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.28'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.28'
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: timers
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.3'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: core-inspect
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -48,10 +62,15 @@ files:
48
62
  - LICENSE
49
63
  - lib/core/async.rb
50
64
  - lib/core/async/bootstrap.rb
65
+ - lib/core/async/cancel.rb
66
+ - lib/core/async/channel.rb
51
67
  - lib/core/async/collection.rb
52
68
  - lib/core/async/enumerator.rb
69
+ - lib/core/async/failure.rb
70
+ - lib/core/async/filament.rb
53
71
  - lib/core/async/future.rb
54
72
  - lib/core/async/reactor.rb
73
+ - lib/core/async/scheduler.rb
55
74
  - lib/core/async/timeout.rb
56
75
  - lib/core/async/version.rb
57
76
  - lib/core/async/wrapper.rb
@@ -68,14 +87,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
87
  requirements:
69
88
  - - ">="
70
89
  - !ruby/object:Gem::Version
71
- version: '2.7'
90
+ version: '3.0'
72
91
  required_rubygems_version: !ruby/object:Gem::Requirement
73
92
  requirements:
74
93
  - - ">="
75
94
  - !ruby/object:Gem::Version
76
95
  version: '0'
77
96
  requirements: []
78
- rubygems_version: 3.2.15
97
+ rubygems_version: 3.2.22
79
98
  signing_key:
80
99
  specification_version: 4
81
100
  summary: Makes Ruby objects async-aware.