core-async 0.8.0 → 0.9.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.
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.