concurrent-ruby 1.1.4 → 1.1.5
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile +9 -7
- data/README.md +34 -2
- data/Rakefile +33 -52
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +9 -8
- data/lib/concurrent/array.rb +3 -3
- data/lib/concurrent/async.rb +14 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +2 -2
- data/lib/concurrent/collection/lock_free_stack.rb +1 -1
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/executor/timer_set.rb +13 -15
- data/lib/concurrent/hash.rb +3 -3
- data/lib/concurrent/promises.rb +348 -117
- data/lib/concurrent/synchronization/abstract_struct.rb +1 -0
- data/lib/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent/synchronization/jruby_object.rb +1 -0
- data/lib/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent/synchronization/mri_object.rb +1 -0
- data/lib/concurrent/synchronization/object.rb +46 -20
- data/lib/concurrent/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent/synchronization/truffleruby_object.rb +1 -0
- data/lib/concurrent/version.rb +1 -2
- metadata +5 -4
    
        data/lib/concurrent/hash.rb
    CHANGED
    
    | @@ -15,8 +15,9 @@ module Concurrent | |
| 15 15 | 
             
              # @!macro internal_implementation_note
         | 
| 16 16 | 
             
              HashImplementation = case
         | 
| 17 17 | 
             
                                   when Concurrent.on_cruby?
         | 
| 18 | 
            -
                                     #  | 
| 19 | 
            -
                                     #  | 
| 18 | 
            +
                                     # Hash is thread-safe in practice because CRuby runs
         | 
| 19 | 
            +
                                     # threads one at a time and does not do context
         | 
| 20 | 
            +
                                     # switching during the execution of C functions.
         | 
| 20 21 | 
             
                                     ::Hash
         | 
| 21 22 |  | 
| 22 23 | 
             
                                   when Concurrent.on_jruby?
         | 
| @@ -56,4 +57,3 @@ module Concurrent | |
| 56 57 | 
             
              end
         | 
| 57 58 |  | 
| 58 59 | 
             
            end
         | 
| 59 | 
            -
             | 
    
        data/lib/concurrent/promises.rb
    CHANGED
    
    | @@ -43,6 +43,7 @@ module Concurrent | |
| 43 43 | 
             
                # new.
         | 
| 44 44 | 
             
                module FactoryMethods
         | 
| 45 45 | 
             
                  extend ReInclude
         | 
| 46 | 
            +
                  extend self
         | 
| 46 47 |  | 
| 47 48 | 
             
                  module Configuration
         | 
| 48 49 | 
             
                    # @return [Executor, :io, :fast] the executor which is used when none is supplied
         | 
| @@ -92,16 +93,14 @@ module Concurrent | |
| 92 93 | 
             
                    future_on(default_executor, *args, &task)
         | 
| 93 94 | 
             
                  end
         | 
| 94 95 |  | 
| 95 | 
            -
                  #  | 
| 96 | 
            -
                  #   Constructs new Future which will be resolved after block is evaluated on default executor.
         | 
| 96 | 
            +
                  # Constructs new Future which will be resolved after block is evaluated on default executor.
         | 
| 97 97 | 
             
                  # Evaluation begins immediately.
         | 
| 98 98 | 
             
                  #
         | 
| 99 | 
            -
                  # @!macro promises. | 
| 100 | 
            -
                  # | 
| 101 | 
            -
                  # | 
| 102 | 
            -
                  # | 
| 103 | 
            -
                  # | 
| 104 | 
            -
                  #   @return [Future]
         | 
| 99 | 
            +
                  # @!macro promises.param.default_executor
         | 
| 100 | 
            +
                  # @!macro promises.param.args
         | 
| 101 | 
            +
                  # @yield [*args] to the task.
         | 
| 102 | 
            +
                  # @!macro promise.param.task-future
         | 
| 103 | 
            +
                  # @return [Future]
         | 
| 105 104 | 
             
                  def future_on(default_executor, *args, &task)
         | 
| 106 105 | 
             
                    ImmediateEventPromise.new(default_executor).future.then(*args, &task)
         | 
| 107 106 | 
             
                  end
         | 
| @@ -109,6 +108,9 @@ module Concurrent | |
| 109 108 | 
             
                  # Creates resolved future with will be either fulfilled with the given value or rejection with
         | 
| 110 109 | 
             
                  # the given reason.
         | 
| 111 110 | 
             
                  #
         | 
| 111 | 
            +
                  # @param [true, false] fulfilled
         | 
| 112 | 
            +
                  # @param [Object] value
         | 
| 113 | 
            +
                  # @param [Object] reason
         | 
| 112 114 | 
             
                  # @!macro promises.param.default_executor
         | 
| 113 115 | 
             
                  # @return [Future]
         | 
| 114 116 | 
             
                  def resolved_future(fulfilled, value, reason, default_executor = self.default_executor)
         | 
| @@ -118,6 +120,7 @@ module Concurrent | |
| 118 120 | 
             
                  # Creates resolved future with will be fulfilled with the given value.
         | 
| 119 121 | 
             
                  #
         | 
| 120 122 | 
             
                  # @!macro promises.param.default_executor
         | 
| 123 | 
            +
                  # @param [Object] value
         | 
| 121 124 | 
             
                  # @return [Future]
         | 
| 122 125 | 
             
                  def fulfilled_future(value, default_executor = self.default_executor)
         | 
| 123 126 | 
             
                    resolved_future true, value, nil, default_executor
         | 
| @@ -126,6 +129,7 @@ module Concurrent | |
| 126 129 | 
             
                  # Creates resolved future with will be rejected with the given reason.
         | 
| 127 130 | 
             
                  #
         | 
| 128 131 | 
             
                  # @!macro promises.param.default_executor
         | 
| 132 | 
            +
                  # @param [Object] reason
         | 
| 129 133 | 
             
                  # @return [Future]
         | 
| 130 134 | 
             
                  def rejected_future(reason, default_executor = self.default_executor)
         | 
| 131 135 | 
             
                    resolved_future false, nil, reason, default_executor
         | 
| @@ -146,23 +150,23 @@ module Concurrent | |
| 146 150 | 
             
                  # @!macro promises.param.default_executor
         | 
| 147 151 | 
             
                  # @return [Event, Future]
         | 
| 148 152 | 
             
                  #
         | 
| 149 | 
            -
                  # @overload  | 
| 153 | 
            +
                  # @overload make_future(nil, default_executor = self.default_executor)
         | 
| 150 154 | 
             
                  #   @param [nil] nil
         | 
| 151 155 | 
             
                  #   @return [Event] resolved event.
         | 
| 152 156 | 
             
                  #
         | 
| 153 | 
            -
                  # @overload  | 
| 157 | 
            +
                  # @overload make_future(a_future, default_executor = self.default_executor)
         | 
| 154 158 | 
             
                  #   @param [Future] a_future
         | 
| 155 159 | 
             
                  #   @return [Future] a future which will be resolved when a_future is.
         | 
| 156 160 | 
             
                  #
         | 
| 157 | 
            -
                  # @overload  | 
| 161 | 
            +
                  # @overload make_future(an_event, default_executor = self.default_executor)
         | 
| 158 162 | 
             
                  #   @param [Event] an_event
         | 
| 159 163 | 
             
                  #   @return [Event] an event which will be resolved when an_event is.
         | 
| 160 164 | 
             
                  #
         | 
| 161 | 
            -
                  # @overload  | 
| 165 | 
            +
                  # @overload make_future(exception, default_executor = self.default_executor)
         | 
| 162 166 | 
             
                  #   @param [Exception] exception
         | 
| 163 167 | 
             
                  #   @return [Future] a rejected future with the exception as its reason.
         | 
| 164 168 | 
             
                  #
         | 
| 165 | 
            -
                  # @overload  | 
| 169 | 
            +
                  # @overload make_future(value, default_executor = self.default_executor)
         | 
| 166 170 | 
             
                  #   @param [Object] value when none of the above overloads fits
         | 
| 167 171 | 
             
                  #   @return [Future] a fulfilled future with the value.
         | 
| 168 172 | 
             
                  def make_future(argument = nil, default_executor = self.default_executor)
         | 
| @@ -180,34 +184,53 @@ module Concurrent | |
| 180 184 | 
             
                  end
         | 
| 181 185 |  | 
| 182 186 | 
             
                  # @!macro promises.shortcut.on
         | 
| 183 | 
            -
                  # @return [Future]
         | 
| 187 | 
            +
                  # @return [Future, Event]
         | 
| 184 188 | 
             
                  def delay(*args, &task)
         | 
| 185 189 | 
             
                    delay_on default_executor, *args, &task
         | 
| 186 190 | 
             
                  end
         | 
| 187 191 |  | 
| 188 | 
            -
                  #  | 
| 189 | 
            -
                  #  | 
| 192 | 
            +
                  # Creates new event or future which is resolved only after it is touched,
         | 
| 193 | 
            +
                  # see {Concurrent::AbstractEventFuture#touch}.
         | 
| 190 194 | 
             
                  #
         | 
| 191 | 
            -
                  # @!macro promises. | 
| 195 | 
            +
                  # @!macro promises.param.default_executor
         | 
| 196 | 
            +
                  # @overload delay_on(default_executor, *args, &task)
         | 
| 197 | 
            +
                  #   If task is provided it returns a {Future} representing the result of the task.
         | 
| 198 | 
            +
                  #   @!macro promises.param.args
         | 
| 199 | 
            +
                  #   @yield [*args] to the task.
         | 
| 200 | 
            +
                  #   @!macro promise.param.task-future
         | 
| 201 | 
            +
                  #   @return [Future]
         | 
| 202 | 
            +
                  # @overload delay_on(default_executor)
         | 
| 203 | 
            +
                  #   If no task is provided, it returns an {Event}
         | 
| 204 | 
            +
                  #   @return [Event]
         | 
| 192 205 | 
             
                  def delay_on(default_executor, *args, &task)
         | 
| 193 | 
            -
                    DelayPromise.new(default_executor).event | 
| 206 | 
            +
                    event = DelayPromise.new(default_executor).event
         | 
| 207 | 
            +
                    task ? event.chain(*args, &task) : event
         | 
| 194 208 | 
             
                  end
         | 
| 195 209 |  | 
| 196 210 | 
             
                  # @!macro promises.shortcut.on
         | 
| 197 | 
            -
                  # @return [Future]
         | 
| 211 | 
            +
                  # @return [Future, Event]
         | 
| 198 212 | 
             
                  def schedule(intended_time, *args, &task)
         | 
| 199 213 | 
             
                    schedule_on default_executor, intended_time, *args, &task
         | 
| 200 214 | 
             
                  end
         | 
| 201 215 |  | 
| 202 | 
            -
                  #  | 
| 203 | 
            -
                  # The task is planned for execution in intended_time.
         | 
| 216 | 
            +
                  # Creates new event or future which is resolved in intended_time.
         | 
| 204 217 | 
             
                  #
         | 
| 205 | 
            -
                  # @!macro promises. | 
| 218 | 
            +
                  # @!macro promises.param.default_executor
         | 
| 206 219 | 
             
                  # @!macro promises.param.intended_time
         | 
| 207 220 | 
             
                  #   @param [Numeric, Time] intended_time `Numeric` means to run in `intended_time` seconds.
         | 
| 208 221 | 
             
                  #     `Time` means to run on `intended_time`.
         | 
| 222 | 
            +
                  # @overload schedule_on(default_executor, intended_time, *args, &task)
         | 
| 223 | 
            +
                  #   If task is provided it returns a {Future} representing the result of the task.
         | 
| 224 | 
            +
                  #   @!macro promises.param.args
         | 
| 225 | 
            +
                  #   @yield [*args] to the task.
         | 
| 226 | 
            +
                  #   @!macro promise.param.task-future
         | 
| 227 | 
            +
                  #   @return [Future]
         | 
| 228 | 
            +
                  # @overload schedule_on(default_executor, intended_time)
         | 
| 229 | 
            +
                  #   If no task is provided, it returns an {Event}
         | 
| 230 | 
            +
                  #   @return [Event]
         | 
| 209 231 | 
             
                  def schedule_on(default_executor, intended_time, *args, &task)
         | 
| 210 | 
            -
                    ScheduledPromise.new(default_executor, intended_time).event | 
| 232 | 
            +
                    event = ScheduledPromise.new(default_executor, intended_time).event
         | 
| 233 | 
            +
                    task ? event.chain(*args, &task) : event
         | 
| 211 234 | 
             
                  end
         | 
| 212 235 |  | 
| 213 236 | 
             
                  # @!macro promises.shortcut.on
         | 
| @@ -259,7 +282,7 @@ module Concurrent | |
| 259 282 | 
             
                  # Creates new future which is resolved after first futures_and_or_events is resolved.
         | 
| 260 283 | 
             
                  # Its result equals result of the first resolved future.
         | 
| 261 284 | 
             
                  # @!macro promises.any-touch
         | 
| 262 | 
            -
                  #   If resolved it does not propagate {AbstractEventFuture#touch}, leaving delayed
         | 
| 285 | 
            +
                  #   If resolved it does not propagate {Concurrent::AbstractEventFuture#touch}, leaving delayed
         | 
| 263 286 | 
             
                  #   futures un-executed if they are not required any more.
         | 
| 264 287 | 
             
                  # @!macro promises.event-conversion
         | 
| 265 288 | 
             
                  #
         | 
| @@ -311,7 +334,7 @@ module Concurrent | |
| 311 334 | 
             
                end
         | 
| 312 335 |  | 
| 313 336 | 
             
                module InternalStates
         | 
| 314 | 
            -
                  #  | 
| 337 | 
            +
                  # @!visibility private
         | 
| 315 338 | 
             
                  class State
         | 
| 316 339 | 
             
                    def resolved?
         | 
| 317 340 | 
             
                      raise NotImplementedError
         | 
| @@ -322,9 +345,7 @@ module Concurrent | |
| 322 345 | 
             
                    end
         | 
| 323 346 | 
             
                  end
         | 
| 324 347 |  | 
| 325 | 
            -
                   | 
| 326 | 
            -
             | 
| 327 | 
            -
                  # @private
         | 
| 348 | 
            +
                  # @!visibility private
         | 
| 328 349 | 
             
                  class Pending < State
         | 
| 329 350 | 
             
                    def resolved?
         | 
| 330 351 | 
             
                      false
         | 
| @@ -335,9 +356,11 @@ module Concurrent | |
| 335 356 | 
             
                    end
         | 
| 336 357 | 
             
                  end
         | 
| 337 358 |  | 
| 338 | 
            -
                   | 
| 359 | 
            +
                  # @!visibility private
         | 
| 360 | 
            +
                  class Reserved < Pending
         | 
| 361 | 
            +
                  end
         | 
| 339 362 |  | 
| 340 | 
            -
                  #  | 
| 363 | 
            +
                  # @!visibility private
         | 
| 341 364 | 
             
                  class ResolvedWithResult < State
         | 
| 342 365 | 
             
                    def resolved?
         | 
| 343 366 | 
             
                      true
         | 
| @@ -368,9 +391,7 @@ module Concurrent | |
| 368 391 | 
             
                    end
         | 
| 369 392 | 
             
                  end
         | 
| 370 393 |  | 
| 371 | 
            -
                   | 
| 372 | 
            -
             | 
| 373 | 
            -
                  # @private
         | 
| 394 | 
            +
                  # @!visibility private
         | 
| 374 395 | 
             
                  class Fulfilled < ResolvedWithResult
         | 
| 375 396 |  | 
| 376 397 | 
             
                    def initialize(value)
         | 
| @@ -398,18 +419,14 @@ module Concurrent | |
| 398 419 | 
             
                    end
         | 
| 399 420 | 
             
                  end
         | 
| 400 421 |  | 
| 401 | 
            -
                   | 
| 402 | 
            -
             | 
| 403 | 
            -
                  # @private
         | 
| 422 | 
            +
                  # @!visibility private
         | 
| 404 423 | 
             
                  class FulfilledArray < Fulfilled
         | 
| 405 424 | 
             
                    def apply(args, block)
         | 
| 406 425 | 
             
                      block.call(*value, *args)
         | 
| 407 426 | 
             
                    end
         | 
| 408 427 | 
             
                  end
         | 
| 409 428 |  | 
| 410 | 
            -
                   | 
| 411 | 
            -
             | 
| 412 | 
            -
                  # @private
         | 
| 429 | 
            +
                  # @!visibility private
         | 
| 413 430 | 
             
                  class Rejected < ResolvedWithResult
         | 
| 414 431 | 
             
                    def initialize(reason)
         | 
| 415 432 | 
             
                      @Reason = reason
         | 
| @@ -436,9 +453,7 @@ module Concurrent | |
| 436 453 | 
             
                    end
         | 
| 437 454 | 
             
                  end
         | 
| 438 455 |  | 
| 439 | 
            -
                   | 
| 440 | 
            -
             | 
| 441 | 
            -
                  # @private
         | 
| 456 | 
            +
                  # @!visibility private
         | 
| 442 457 | 
             
                  class PartiallyRejected < ResolvedWithResult
         | 
| 443 458 | 
             
                    def initialize(value, reason)
         | 
| 444 459 | 
             
                      super()
         | 
| @@ -467,24 +482,38 @@ module Concurrent | |
| 467 482 | 
             
                    end
         | 
| 468 483 | 
             
                  end
         | 
| 469 484 |  | 
| 470 | 
            -
                   | 
| 471 | 
            -
             | 
| 472 | 
            -
                   | 
| 485 | 
            +
                  # @!visibility private
         | 
| 486 | 
            +
                  PENDING = Pending.new
         | 
| 487 | 
            +
                  # @!visibility private
         | 
| 488 | 
            +
                  RESERVED = Reserved.new
         | 
| 489 | 
            +
                  # @!visibility private
         | 
| 473 490 | 
             
                  RESOLVED = Fulfilled.new(nil)
         | 
| 474 491 |  | 
| 475 492 | 
             
                  def RESOLVED.to_sym
         | 
| 476 493 | 
             
                    :resolved
         | 
| 477 494 | 
             
                  end
         | 
| 478 | 
            -
             | 
| 479 | 
            -
                  private_constant :PENDING, :RESOLVED
         | 
| 480 495 | 
             
                end
         | 
| 481 496 |  | 
| 482 497 | 
             
                private_constant :InternalStates
         | 
| 483 498 |  | 
| 499 | 
            +
                # @!macro promises.shortcut.event-future
         | 
| 500 | 
            +
                #   @see Event#$0
         | 
| 501 | 
            +
                #   @see Future#$0
         | 
| 502 | 
            +
             | 
| 503 | 
            +
                # @!macro promises.param.timeout
         | 
| 504 | 
            +
                #   @param [Numeric] timeout the maximum time in second to wait.
         | 
| 505 | 
            +
             | 
| 506 | 
            +
                # @!macro promises.warn.blocks
         | 
| 507 | 
            +
                #   @note This function potentially blocks current thread until the Future is resolved.
         | 
| 508 | 
            +
                #     Be careful it can deadlock. Try to chain instead.
         | 
| 509 | 
            +
             | 
| 484 510 | 
             
                # Common ancestor of {Event} and {Future} classes, many shared methods are defined here.
         | 
| 485 511 | 
             
                class AbstractEventFuture < Synchronization::Object
         | 
| 486 512 | 
             
                  safe_initialization!
         | 
| 487 | 
            -
                   | 
| 513 | 
            +
                  attr_atomic(:internal_state)
         | 
| 514 | 
            +
                  private :internal_state=, :swap_internal_state, :compare_and_set_internal_state, :update_internal_state
         | 
| 515 | 
            +
                  # @!method internal_state
         | 
| 516 | 
            +
                  #   @!visibility private
         | 
| 488 517 |  | 
| 489 518 | 
             
                  include InternalStates
         | 
| 490 519 |  | 
| @@ -501,17 +530,6 @@ module Concurrent | |
| 501 530 |  | 
| 502 531 | 
             
                  private :initialize
         | 
| 503 532 |  | 
| 504 | 
            -
                  # @!macro promises.shortcut.event-future
         | 
| 505 | 
            -
                  #   @see Event#$0
         | 
| 506 | 
            -
                  #   @see Future#$0
         | 
| 507 | 
            -
             | 
| 508 | 
            -
                  # @!macro promises.param.timeout
         | 
| 509 | 
            -
                  #   @param [Numeric] timeout the maximum time in second to wait.
         | 
| 510 | 
            -
             | 
| 511 | 
            -
                  # @!macro promises.warn.blocks
         | 
| 512 | 
            -
                  #   @note This function potentially blocks current thread until the Future is resolved.
         | 
| 513 | 
            -
                  #     Be careful it can deadlock. Try to chain instead.
         | 
| 514 | 
            -
             | 
| 515 533 | 
             
                  # Returns its state.
         | 
| 516 534 | 
             
                  # @return [Symbol]
         | 
| 517 535 | 
             
                  #
         | 
| @@ -545,7 +563,7 @@ module Concurrent | |
| 545 563 | 
             
                  end
         | 
| 546 564 |  | 
| 547 565 | 
             
                  # @!macro promises.touches
         | 
| 548 | 
            -
                  #   Calls {AbstractEventFuture#touch}.
         | 
| 566 | 
            +
                  #   Calls {Concurrent::AbstractEventFuture#touch}.
         | 
| 549 567 |  | 
| 550 568 | 
             
                  # @!macro promises.method.wait
         | 
| 551 569 | 
             
                  #   Wait (block the Thread) until receiver is {#resolved?}.
         | 
| @@ -553,7 +571,7 @@ module Concurrent | |
| 553 571 | 
             
                  #
         | 
| 554 572 | 
             
                  #   @!macro promises.warn.blocks
         | 
| 555 573 | 
             
                  #   @!macro promises.param.timeout
         | 
| 556 | 
            -
                  #   @return [ | 
| 574 | 
            +
                  #   @return [self, true, false] self implies timeout was not used, true implies timeout was used
         | 
| 557 575 | 
             
                  #     and it was resolved, false implies it was not resolved within timeout.
         | 
| 558 576 | 
             
                  def wait(timeout = nil)
         | 
| 559 577 | 
             
                    result = wait_until_resolved(timeout)
         | 
| @@ -590,7 +608,7 @@ module Concurrent | |
| 590 608 | 
             
                  #   @yield [fulfilled, value, reason, *args] to the task.
         | 
| 591 609 | 
             
                  #   @yieldparam [true, false] fulfilled
         | 
| 592 610 | 
             
                  #   @yieldparam [Object] value
         | 
| 593 | 
            -
                  #   @yieldparam [ | 
| 611 | 
            +
                  #   @yieldparam [Object] reason
         | 
| 594 612 | 
             
                  def chain_on(executor, *args, &task)
         | 
| 595 613 | 
             
                    ChainPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
         | 
| 596 614 | 
             
                  end
         | 
| @@ -631,7 +649,7 @@ module Concurrent | |
| 631 649 | 
             
                  #   @yield [fulfilled, value, reason, *args] to the callback.
         | 
| 632 650 | 
             
                  #   @yieldparam [true, false] fulfilled
         | 
| 633 651 | 
             
                  #   @yieldparam [Object] value
         | 
| 634 | 
            -
                  #   @yieldparam [ | 
| 652 | 
            +
                  #   @yieldparam [Object] reason
         | 
| 635 653 | 
             
                  def on_resolution!(*args, &callback)
         | 
| 636 654 | 
             
                    add_callback :callback_on_resolution, args, callback
         | 
| 637 655 | 
             
                  end
         | 
| @@ -649,7 +667,7 @@ module Concurrent | |
| 649 667 | 
             
                  #   @yield [fulfilled, value, reason, *args] to the callback.
         | 
| 650 668 | 
             
                  #   @yieldparam [true, false] fulfilled
         | 
| 651 669 | 
             
                  #   @yieldparam [Object] value
         | 
| 652 | 
            -
                  #   @yieldparam [ | 
| 670 | 
            +
                  #   @yieldparam [Object] reason
         | 
| 653 671 | 
             
                  def on_resolution_using(executor, *args, &callback)
         | 
| 654 672 | 
             
                    add_callback :async_callback_on_resolution, executor, args, callback
         | 
| 655 673 | 
             
                  end
         | 
| @@ -665,8 +683,8 @@ module Concurrent | |
| 665 683 | 
             
                  end
         | 
| 666 684 |  | 
| 667 685 | 
             
                  # @!visibility private
         | 
| 668 | 
            -
                  def resolve_with(state, raise_on_reassign = true)
         | 
| 669 | 
            -
                    if compare_and_set_internal_state(PENDING, state)
         | 
| 686 | 
            +
                  def resolve_with(state, raise_on_reassign = true, reserved = false)
         | 
| 687 | 
            +
                    if compare_and_set_internal_state(reserved ? RESERVED : PENDING, state)
         | 
| 670 688 | 
             
                      # go to synchronized block only if there were waiting threads
         | 
| 671 689 | 
             
                      @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0
         | 
| 672 690 | 
             
                      call_callbacks state
         | 
| @@ -719,6 +737,12 @@ module Concurrent | |
| 719 737 | 
             
                    add_callback(:callback_clear_delayed_node, node)
         | 
| 720 738 | 
             
                  end
         | 
| 721 739 |  | 
| 740 | 
            +
                  # @!visibility private
         | 
| 741 | 
            +
                  def with_hidden_resolvable
         | 
| 742 | 
            +
                    # TODO (pitr-ch 10-Dec-2018): documentation, better name if in edge
         | 
| 743 | 
            +
                    self
         | 
| 744 | 
            +
                  end
         | 
| 745 | 
            +
             | 
| 722 746 | 
             
                  private
         | 
| 723 747 |  | 
| 724 748 | 
             
                  def add_callback(method, *args)
         | 
| @@ -907,9 +931,17 @@ module Concurrent | |
| 907 931 | 
             
                  #   @!macro promises.warn.blocks
         | 
| 908 932 | 
             
                  #   @!macro promises.warn.nil
         | 
| 909 933 | 
             
                  #   @!macro promises.param.timeout
         | 
| 910 | 
            -
                  #  | 
| 911 | 
            -
                   | 
| 912 | 
            -
             | 
| 934 | 
            +
                  #   @!macro promises.param.timeout_value
         | 
| 935 | 
            +
                  #     @param [Object] timeout_value a value returned by the method when it times out
         | 
| 936 | 
            +
                  # @return [Object, nil, timeout_value] the value of the Future when fulfilled,
         | 
| 937 | 
            +
                  #   timeout_value on timeout,
         | 
| 938 | 
            +
                  #   nil on rejection.
         | 
| 939 | 
            +
                  def value(timeout = nil, timeout_value = nil)
         | 
| 940 | 
            +
                    if wait_until_resolved timeout
         | 
| 941 | 
            +
                      internal_state.value
         | 
| 942 | 
            +
                    else
         | 
| 943 | 
            +
                      timeout_value
         | 
| 944 | 
            +
                    end
         | 
| 913 945 | 
             
                  end
         | 
| 914 946 |  | 
| 915 947 | 
             
                  # Returns reason of future's rejection.
         | 
| @@ -918,9 +950,14 @@ module Concurrent | |
| 918 950 | 
             
                  # @!macro promises.warn.blocks
         | 
| 919 951 | 
             
                  # @!macro promises.warn.nil
         | 
| 920 952 | 
             
                  # @!macro promises.param.timeout
         | 
| 921 | 
            -
                  #  | 
| 922 | 
            -
                   | 
| 923 | 
            -
             | 
| 953 | 
            +
                  # @!macro promises.param.timeout_value
         | 
| 954 | 
            +
                  # @return [Object, timeout_value] the reason, or timeout_value on timeout, or nil on fulfillment.
         | 
| 955 | 
            +
                  def reason(timeout = nil, timeout_value = nil)
         | 
| 956 | 
            +
                    if wait_until_resolved timeout
         | 
| 957 | 
            +
                      internal_state.reason
         | 
| 958 | 
            +
                    else
         | 
| 959 | 
            +
                      timeout_value
         | 
| 960 | 
            +
                    end
         | 
| 924 961 | 
             
                  end
         | 
| 925 962 |  | 
| 926 963 | 
             
                  # Returns triplet fulfilled?, value, reason.
         | 
| @@ -928,7 +965,7 @@ module Concurrent | |
| 928 965 | 
             
                  #
         | 
| 929 966 | 
             
                  # @!macro promises.warn.blocks
         | 
| 930 967 | 
             
                  # @!macro promises.param.timeout
         | 
| 931 | 
            -
                  # @return [Array(Boolean, Object,  | 
| 968 | 
            +
                  # @return [Array(Boolean, Object, Object), nil] triplet of fulfilled?, value, reason, or nil
         | 
| 932 969 | 
             
                  #   on timeout.
         | 
| 933 970 | 
             
                  def result(timeout = nil)
         | 
| 934 971 | 
             
                    internal_state.result if wait_until_resolved timeout
         | 
| @@ -942,26 +979,40 @@ module Concurrent | |
| 942 979 | 
             
                  end
         | 
| 943 980 |  | 
| 944 981 | 
             
                  # @!macro promises.method.value
         | 
| 945 | 
            -
                  # @return [Object, nil] the value of the Future when fulfilled, | 
| 982 | 
            +
                  # @return [Object, nil, timeout_value] the value of the Future when fulfilled,
         | 
| 983 | 
            +
                  #   or nil on rejection,
         | 
| 984 | 
            +
                  #   or timeout_value on timeout.
         | 
| 946 985 | 
             
                  # @raise [Exception] {#reason} on rejection
         | 
| 947 | 
            -
                  def value!(timeout = nil)
         | 
| 948 | 
            -
                     | 
| 986 | 
            +
                  def value!(timeout = nil, timeout_value = nil)
         | 
| 987 | 
            +
                    if wait_until_resolved! timeout
         | 
| 988 | 
            +
                      internal_state.value
         | 
| 989 | 
            +
                    else
         | 
| 990 | 
            +
                      timeout_value
         | 
| 991 | 
            +
                    end
         | 
| 949 992 | 
             
                  end
         | 
| 950 993 |  | 
| 951 994 | 
             
                  # Allows rejected Future to be risen with `raise` method.
         | 
| 995 | 
            +
                  # If the reason is not an exception `Runtime.new(reason)` is returned.
         | 
| 996 | 
            +
                  #
         | 
| 952 997 | 
             
                  # @example
         | 
| 953 998 | 
             
                  #   raise Promises.rejected_future(StandardError.new("boom"))
         | 
| 954 | 
            -
                  # | 
| 999 | 
            +
                  #   raise Promises.rejected_future("or just boom")
         | 
| 1000 | 
            +
                  # @raise [Concurrent::Error] when raising not rejected future
         | 
| 955 1001 | 
             
                  # @return [Exception]
         | 
| 956 1002 | 
             
                  def exception(*args)
         | 
| 957 1003 | 
             
                    raise Concurrent::Error, 'it is not rejected' unless rejected?
         | 
| 1004 | 
            +
                    raise ArgumentError unless args.size <= 1
         | 
| 958 1005 | 
             
                    reason = Array(internal_state.reason).flatten.compact
         | 
| 959 1006 | 
             
                    if reason.size > 1
         | 
| 960 1007 | 
             
                      ex = Concurrent::MultipleErrors.new reason
         | 
| 961 1008 | 
             
                      ex.set_backtrace(caller)
         | 
| 962 1009 | 
             
                      ex
         | 
| 963 1010 | 
             
                    else
         | 
| 964 | 
            -
                      ex = reason[0]. | 
| 1011 | 
            +
                      ex = if reason[0].respond_to? :exception
         | 
| 1012 | 
            +
                             reason[0].exception(*args)
         | 
| 1013 | 
            +
                           else
         | 
| 1014 | 
            +
                             RuntimeError.new(reason[0]).exception(*args)
         | 
| 1015 | 
            +
                           end
         | 
| 965 1016 | 
             
                      ex.set_backtrace Array(ex.backtrace) + caller
         | 
| 966 1017 | 
             
                      ex
         | 
| 967 1018 | 
             
                    end
         | 
| @@ -1133,14 +1184,20 @@ module Concurrent | |
| 1133 1184 | 
             
                  # will become reason of the returned future.
         | 
| 1134 1185 | 
             
                  #
         | 
| 1135 1186 | 
             
                  # @return [Future]
         | 
| 1187 | 
            +
                  # @param [#call(value)] run_test
         | 
| 1188 | 
            +
                  #   an object which when called returns either Future to keep running with
         | 
| 1189 | 
            +
                  #   or nil, then the run completes with the value.
         | 
| 1190 | 
            +
                  #   The run_test can be used to extract the Future from deeper structure,
         | 
| 1191 | 
            +
                  #   or to distinguish Future which is a resulting value from a future
         | 
| 1192 | 
            +
                  #   which is suppose to continue running.
         | 
| 1136 1193 | 
             
                  # @example
         | 
| 1137 1194 | 
             
                  #   body = lambda do |v|
         | 
| 1138 1195 | 
             
                  #     v += 1
         | 
| 1139 1196 | 
             
                  #     v < 5 ? Promises.future(v, &body) : v
         | 
| 1140 1197 | 
             
                  #   end
         | 
| 1141 1198 | 
             
                  #   Promises.future(0, &body).run.value! # => 5
         | 
| 1142 | 
            -
                  def run
         | 
| 1143 | 
            -
                    RunFuturePromise.new_blocked_by1(self, @DefaultExecutor).future
         | 
| 1199 | 
            +
                  def run(run_test = method(:run_test))
         | 
| 1200 | 
            +
                    RunFuturePromise.new_blocked_by1(self, @DefaultExecutor, run_test).future
         | 
| 1144 1201 | 
             
                  end
         | 
| 1145 1202 |  | 
| 1146 1203 | 
             
                  # @!visibility private
         | 
| @@ -1163,13 +1220,34 @@ module Concurrent | |
| 1163 1220 | 
             
                    self
         | 
| 1164 1221 | 
             
                  end
         | 
| 1165 1222 |  | 
| 1223 | 
            +
                  # @return [String] Short string representation.
         | 
| 1224 | 
            +
                  def to_s
         | 
| 1225 | 
            +
                    if resolved?
         | 
| 1226 | 
            +
                      format '%s with %s>', super[0..-2], (fulfilled? ? value : reason).inspect
         | 
| 1227 | 
            +
                    else
         | 
| 1228 | 
            +
                      super
         | 
| 1229 | 
            +
                    end
         | 
| 1230 | 
            +
                  end
         | 
| 1231 | 
            +
             | 
| 1232 | 
            +
                  alias_method :inspect, :to_s
         | 
| 1233 | 
            +
             | 
| 1166 1234 | 
             
                  private
         | 
| 1167 1235 |  | 
| 1236 | 
            +
                  def run_test(v)
         | 
| 1237 | 
            +
                    v if v.is_a?(Future)
         | 
| 1238 | 
            +
                  end
         | 
| 1239 | 
            +
             | 
| 1168 1240 | 
             
                  def rejected_resolution(raise_on_reassign, state)
         | 
| 1169 1241 | 
             
                    if raise_on_reassign
         | 
| 1170 | 
            -
                       | 
| 1171 | 
            -
             | 
| 1172 | 
            -
             | 
| 1242 | 
            +
                      if internal_state == RESERVED
         | 
| 1243 | 
            +
                        raise Concurrent::MultipleAssignmentError.new(
         | 
| 1244 | 
            +
                            "Future can be resolved only once. It is already reserved.")
         | 
| 1245 | 
            +
                      else
         | 
| 1246 | 
            +
                        raise Concurrent::MultipleAssignmentError.new(
         | 
| 1247 | 
            +
                            "Future can be resolved only once. It's #{result}, trying to set #{state.result}.",
         | 
| 1248 | 
            +
                            current_result: result,
         | 
| 1249 | 
            +
                            new_result:     state.result)
         | 
| 1250 | 
            +
                      end
         | 
| 1173 1251 | 
             
                    end
         | 
| 1174 1252 | 
             
                    return false
         | 
| 1175 1253 | 
             
                  end
         | 
| @@ -1206,15 +1284,15 @@ module Concurrent | |
| 1206 1284 |  | 
| 1207 1285 | 
             
                end
         | 
| 1208 1286 |  | 
| 1209 | 
            -
                # Marker module of Future, Event resolved manually | 
| 1287 | 
            +
                # Marker module of Future, Event resolved manually.
         | 
| 1210 1288 | 
             
                module Resolvable
         | 
| 1289 | 
            +
                  include InternalStates
         | 
| 1211 1290 | 
             
                end
         | 
| 1212 1291 |  | 
| 1213 1292 | 
             
                # A Event which can be resolved by user.
         | 
| 1214 1293 | 
             
                class ResolvableEvent < Event
         | 
| 1215 1294 | 
             
                  include Resolvable
         | 
| 1216 1295 |  | 
| 1217 | 
            -
             | 
| 1218 1296 | 
             
                  # @!macro raise_on_reassign
         | 
| 1219 1297 | 
             
                  # @raise [MultipleAssignmentError] when already resolved and raise_on_reassign is true.
         | 
| 1220 1298 |  | 
| @@ -1227,8 +1305,13 @@ module Concurrent | |
| 1227 1305 | 
             
                  # Makes the event resolved, which triggers all dependent futures.
         | 
| 1228 1306 | 
             
                  #
         | 
| 1229 1307 | 
             
                  # @!macro promise.param.raise_on_reassign
         | 
| 1230 | 
            -
                   | 
| 1231 | 
            -
             | 
| 1308 | 
            +
                  # @!macro promise.param.reserved
         | 
| 1309 | 
            +
                  #   @param [true, false] reserved
         | 
| 1310 | 
            +
                  #     Set to true if the resolvable is {#reserve}d by you,
         | 
| 1311 | 
            +
                  #     marks resolution of reserved resolvable events and futures explicitly.
         | 
| 1312 | 
            +
                  #     Advanced feature, ignore unless you use {Resolvable#reserve} from edge.
         | 
| 1313 | 
            +
                  def resolve(raise_on_reassign = true, reserved = false)
         | 
| 1314 | 
            +
                    resolve_with RESOLVED, raise_on_reassign, reserved
         | 
| 1232 1315 | 
             
                  end
         | 
| 1233 1316 |  | 
| 1234 1317 | 
             
                  # Creates new event wrapping receiver, effectively hiding the resolve method.
         | 
| @@ -1237,6 +1320,23 @@ module Concurrent | |
| 1237 1320 | 
             
                  def with_hidden_resolvable
         | 
| 1238 1321 | 
             
                    @with_hidden_resolvable ||= EventWrapperPromise.new_blocked_by1(self, @DefaultExecutor).event
         | 
| 1239 1322 | 
             
                  end
         | 
| 1323 | 
            +
             | 
| 1324 | 
            +
                  # Behaves as {AbstractEventFuture#wait} but has one additional optional argument
         | 
| 1325 | 
            +
                  # resolve_on_timeout.
         | 
| 1326 | 
            +
                  #
         | 
| 1327 | 
            +
                  # @param [true, false] resolve_on_timeout
         | 
| 1328 | 
            +
                  #   If it times out and the argument is true it will also resolve the event.
         | 
| 1329 | 
            +
                  # @return [self, true, false]
         | 
| 1330 | 
            +
                  # @see AbstractEventFuture#wait
         | 
| 1331 | 
            +
                  def wait(timeout = nil, resolve_on_timeout = false)
         | 
| 1332 | 
            +
                    super(timeout) or if resolve_on_timeout
         | 
| 1333 | 
            +
                                        # if it fails to resolve it was resolved in the meantime
         | 
| 1334 | 
            +
                                        # so return true as if there was no timeout
         | 
| 1335 | 
            +
                                        !resolve(false)
         | 
| 1336 | 
            +
                                      else
         | 
| 1337 | 
            +
                                        false
         | 
| 1338 | 
            +
                                      end
         | 
| 1339 | 
            +
                  end
         | 
| 1240 1340 | 
             
                end
         | 
| 1241 1341 |  | 
| 1242 1342 | 
             
                # A Future which can be resolved by user.
         | 
| @@ -1246,29 +1346,38 @@ module Concurrent | |
| 1246 1346 | 
             
                  # Makes the future resolved with result of triplet `fulfilled?`, `value`, `reason`,
         | 
| 1247 1347 | 
             
                  # which triggers all dependent futures.
         | 
| 1248 1348 | 
             
                  #
         | 
| 1349 | 
            +
                  # @param [true, false] fulfilled
         | 
| 1350 | 
            +
                  # @param [Object] value
         | 
| 1351 | 
            +
                  # @param [Object] reason
         | 
| 1249 1352 | 
             
                  # @!macro promise.param.raise_on_reassign
         | 
| 1250 | 
            -
                   | 
| 1251 | 
            -
             | 
| 1353 | 
            +
                  # @!macro promise.param.reserved
         | 
| 1354 | 
            +
                  def resolve(fulfilled = true, value = nil, reason = nil, raise_on_reassign = true, reserved = false)
         | 
| 1355 | 
            +
                    resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason), raise_on_reassign, reserved)
         | 
| 1252 1356 | 
             
                  end
         | 
| 1253 1357 |  | 
| 1254 1358 | 
             
                  # Makes the future fulfilled with `value`,
         | 
| 1255 1359 | 
             
                  # which triggers all dependent futures.
         | 
| 1256 1360 | 
             
                  #
         | 
| 1361 | 
            +
                  # @param [Object] value
         | 
| 1257 1362 | 
             
                  # @!macro promise.param.raise_on_reassign
         | 
| 1258 | 
            -
                   | 
| 1259 | 
            -
             | 
| 1363 | 
            +
                  # @!macro promise.param.reserved
         | 
| 1364 | 
            +
                  def fulfill(value, raise_on_reassign = true, reserved = false)
         | 
| 1365 | 
            +
                    resolve_with Fulfilled.new(value), raise_on_reassign, reserved
         | 
| 1260 1366 | 
             
                  end
         | 
| 1261 1367 |  | 
| 1262 1368 | 
             
                  # Makes the future rejected with `reason`,
         | 
| 1263 1369 | 
             
                  # which triggers all dependent futures.
         | 
| 1264 1370 | 
             
                  #
         | 
| 1371 | 
            +
                  # @param [Object] reason
         | 
| 1265 1372 | 
             
                  # @!macro promise.param.raise_on_reassign
         | 
| 1266 | 
            -
                   | 
| 1267 | 
            -
             | 
| 1373 | 
            +
                  # @!macro promise.param.reserved
         | 
| 1374 | 
            +
                  def reject(reason, raise_on_reassign = true, reserved = false)
         | 
| 1375 | 
            +
                    resolve_with Rejected.new(reason), raise_on_reassign, reserved
         | 
| 1268 1376 | 
             
                  end
         | 
| 1269 1377 |  | 
| 1270 1378 | 
             
                  # Evaluates the block and sets its result as future's value fulfilling, if the block raises
         | 
| 1271 1379 | 
             
                  # an exception the future rejects with it.
         | 
| 1380 | 
            +
                  #
         | 
| 1272 1381 | 
             
                  # @yield [*args] to the block.
         | 
| 1273 1382 | 
             
                  # @yieldreturn [Object] value
         | 
| 1274 1383 | 
             
                  # @return [self]
         | 
| @@ -1278,6 +1387,7 @@ module Concurrent | |
| 1278 1387 |  | 
| 1279 1388 | 
             
                  # Evaluates the block and sets its result as future's value fulfilling, if the block raises
         | 
| 1280 1389 | 
             
                  # an exception the future rejects with it.
         | 
| 1390 | 
            +
                  #
         | 
| 1281 1391 | 
             
                  # @yield [*args] to the block.
         | 
| 1282 1392 | 
             
                  # @yieldreturn [Object] value
         | 
| 1283 1393 | 
             
                  # @return [self]
         | 
| @@ -1286,6 +1396,135 @@ module Concurrent | |
| 1286 1396 | 
             
                    promise.evaluate_to(*args, block).wait!
         | 
| 1287 1397 | 
             
                  end
         | 
| 1288 1398 |  | 
| 1399 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1400 | 
            +
                  #   @param [::Array(true, Object, nil), ::Array(false, nil, Exception), nil] resolve_on_timeout
         | 
| 1401 | 
            +
                  #     If it times out and the argument is not nil it will also resolve the future
         | 
| 1402 | 
            +
                  #     to the provided resolution.
         | 
| 1403 | 
            +
             | 
| 1404 | 
            +
                  # Behaves as {AbstractEventFuture#wait} but has one additional optional argument
         | 
| 1405 | 
            +
                  # resolve_on_timeout.
         | 
| 1406 | 
            +
                  #
         | 
| 1407 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1408 | 
            +
                  # @return [self, true, false]
         | 
| 1409 | 
            +
                  # @see AbstractEventFuture#wait
         | 
| 1410 | 
            +
                  def wait(timeout = nil, resolve_on_timeout = nil)
         | 
| 1411 | 
            +
                    super(timeout) or if resolve_on_timeout
         | 
| 1412 | 
            +
                                        # if it fails to resolve it was resolved in the meantime
         | 
| 1413 | 
            +
                                        # so return true as if there was no timeout
         | 
| 1414 | 
            +
                                        !resolve(*resolve_on_timeout, false)
         | 
| 1415 | 
            +
                                      else
         | 
| 1416 | 
            +
                                        false
         | 
| 1417 | 
            +
                                      end
         | 
| 1418 | 
            +
                  end
         | 
| 1419 | 
            +
             | 
| 1420 | 
            +
                  # Behaves as {Future#wait!} but has one additional optional argument
         | 
| 1421 | 
            +
                  # resolve_on_timeout.
         | 
| 1422 | 
            +
                  #
         | 
| 1423 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1424 | 
            +
                  # @return [self, true, false]
         | 
| 1425 | 
            +
                  # @raise [Exception] {#reason} on rejection
         | 
| 1426 | 
            +
                  # @see Future#wait!
         | 
| 1427 | 
            +
                  def wait!(timeout = nil, resolve_on_timeout = nil)
         | 
| 1428 | 
            +
                    super(timeout) or if resolve_on_timeout
         | 
| 1429 | 
            +
                                        if resolve(*resolve_on_timeout, false)
         | 
| 1430 | 
            +
                                          false
         | 
| 1431 | 
            +
                                        else
         | 
| 1432 | 
            +
                                          # if it fails to resolve it was resolved in the meantime
         | 
| 1433 | 
            +
                                          # so return true as if there was no timeout
         | 
| 1434 | 
            +
                                          raise self if rejected?
         | 
| 1435 | 
            +
                                          true
         | 
| 1436 | 
            +
                                        end
         | 
| 1437 | 
            +
                                      else
         | 
| 1438 | 
            +
                                        false
         | 
| 1439 | 
            +
                                      end
         | 
| 1440 | 
            +
                  end
         | 
| 1441 | 
            +
             | 
| 1442 | 
            +
                  # Behaves as {Future#value} but has one additional optional argument
         | 
| 1443 | 
            +
                  # resolve_on_timeout.
         | 
| 1444 | 
            +
                  #
         | 
| 1445 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1446 | 
            +
                  # @return [Object, timeout_value, nil]
         | 
| 1447 | 
            +
                  # @see Future#value
         | 
| 1448 | 
            +
                  def value(timeout = nil, timeout_value = nil, resolve_on_timeout = nil)
         | 
| 1449 | 
            +
                    if wait_until_resolved timeout
         | 
| 1450 | 
            +
                      internal_state.value
         | 
| 1451 | 
            +
                    else
         | 
| 1452 | 
            +
                      if resolve_on_timeout
         | 
| 1453 | 
            +
                        unless resolve(*resolve_on_timeout, false)
         | 
| 1454 | 
            +
                          # if it fails to resolve it was resolved in the meantime
         | 
| 1455 | 
            +
                          # so return value as if there was no timeout
         | 
| 1456 | 
            +
                          return internal_state.value
         | 
| 1457 | 
            +
                        end
         | 
| 1458 | 
            +
                      end
         | 
| 1459 | 
            +
                      timeout_value
         | 
| 1460 | 
            +
                    end
         | 
| 1461 | 
            +
                  end
         | 
| 1462 | 
            +
             | 
| 1463 | 
            +
                  # Behaves as {Future#value!} but has one additional optional argument
         | 
| 1464 | 
            +
                  # resolve_on_timeout.
         | 
| 1465 | 
            +
                  #
         | 
| 1466 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1467 | 
            +
                  # @return [Object, timeout_value, nil]
         | 
| 1468 | 
            +
                  # @raise [Exception] {#reason} on rejection
         | 
| 1469 | 
            +
                  # @see Future#value!
         | 
| 1470 | 
            +
                  def value!(timeout = nil, timeout_value = nil, resolve_on_timeout = nil)
         | 
| 1471 | 
            +
                    if wait_until_resolved! timeout
         | 
| 1472 | 
            +
                      internal_state.value
         | 
| 1473 | 
            +
                    else
         | 
| 1474 | 
            +
                      if resolve_on_timeout
         | 
| 1475 | 
            +
                        unless resolve(*resolve_on_timeout, false)
         | 
| 1476 | 
            +
                          # if it fails to resolve it was resolved in the meantime
         | 
| 1477 | 
            +
                          # so return value as if there was no timeout
         | 
| 1478 | 
            +
                          raise self if rejected?
         | 
| 1479 | 
            +
                          return internal_state.value
         | 
| 1480 | 
            +
                        end
         | 
| 1481 | 
            +
                      end
         | 
| 1482 | 
            +
                      timeout_value
         | 
| 1483 | 
            +
                    end
         | 
| 1484 | 
            +
                  end
         | 
| 1485 | 
            +
             | 
| 1486 | 
            +
                  # Behaves as {Future#reason} but has one additional optional argument
         | 
| 1487 | 
            +
                  # resolve_on_timeout.
         | 
| 1488 | 
            +
                  #
         | 
| 1489 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1490 | 
            +
                  # @return [Exception, timeout_value, nil]
         | 
| 1491 | 
            +
                  # @see Future#reason
         | 
| 1492 | 
            +
                  def reason(timeout = nil, timeout_value = nil, resolve_on_timeout = nil)
         | 
| 1493 | 
            +
                    if wait_until_resolved timeout
         | 
| 1494 | 
            +
                      internal_state.reason
         | 
| 1495 | 
            +
                    else
         | 
| 1496 | 
            +
                      if resolve_on_timeout
         | 
| 1497 | 
            +
                        unless resolve(*resolve_on_timeout, false)
         | 
| 1498 | 
            +
                          # if it fails to resolve it was resolved in the meantime
         | 
| 1499 | 
            +
                          # so return value as if there was no timeout
         | 
| 1500 | 
            +
                          return internal_state.reason
         | 
| 1501 | 
            +
                        end
         | 
| 1502 | 
            +
                      end
         | 
| 1503 | 
            +
                      timeout_value
         | 
| 1504 | 
            +
                    end
         | 
| 1505 | 
            +
                  end
         | 
| 1506 | 
            +
             | 
| 1507 | 
            +
                  # Behaves as {Future#result} but has one additional optional argument
         | 
| 1508 | 
            +
                  # resolve_on_timeout.
         | 
| 1509 | 
            +
                  #
         | 
| 1510 | 
            +
                  # @!macro promises.resolvable.resolve_on_timeout
         | 
| 1511 | 
            +
                  # @return [::Array(Boolean, Object, Exception), nil]
         | 
| 1512 | 
            +
                  # @see Future#result
         | 
| 1513 | 
            +
                  def result(timeout = nil, resolve_on_timeout = nil)
         | 
| 1514 | 
            +
                    if wait_until_resolved timeout
         | 
| 1515 | 
            +
                      internal_state.result
         | 
| 1516 | 
            +
                    else
         | 
| 1517 | 
            +
                      if resolve_on_timeout
         | 
| 1518 | 
            +
                        unless resolve(*resolve_on_timeout, false)
         | 
| 1519 | 
            +
                          # if it fails to resolve it was resolved in the meantime
         | 
| 1520 | 
            +
                          # so return value as if there was no timeout
         | 
| 1521 | 
            +
                          internal_state.result
         | 
| 1522 | 
            +
                        end
         | 
| 1523 | 
            +
                      end
         | 
| 1524 | 
            +
                      # otherwise returns nil
         | 
| 1525 | 
            +
                    end
         | 
| 1526 | 
            +
                  end
         | 
| 1527 | 
            +
             | 
| 1289 1528 | 
             
                  # Creates new future wrapping receiver, effectively hiding the resolve method and similar.
         | 
| 1290 1529 | 
             
                  #
         | 
| 1291 1530 | 
             
                  # @return [Future]
         | 
| @@ -1358,14 +1597,6 @@ module Concurrent | |
| 1358 1597 | 
             
                    super ResolvableFuture.new(self, default_executor)
         | 
| 1359 1598 | 
             
                  end
         | 
| 1360 1599 |  | 
| 1361 | 
            -
                  def fulfill(value, raise_on_reassign)
         | 
| 1362 | 
            -
                    resolve_with Fulfilled.new(value), raise_on_reassign
         | 
| 1363 | 
            -
                  end
         | 
| 1364 | 
            -
             | 
| 1365 | 
            -
                  def reject(reason, raise_on_reassign)
         | 
| 1366 | 
            -
                    resolve_with Rejected.new(reason), raise_on_reassign
         | 
| 1367 | 
            -
                  end
         | 
| 1368 | 
            -
             | 
| 1369 1600 | 
             
                  public :evaluate_to
         | 
| 1370 1601 | 
             
                end
         | 
| 1371 1602 |  | 
| @@ -1615,7 +1846,7 @@ module Concurrent | |
| 1615 1846 |  | 
| 1616 1847 | 
             
                      value = internal_state.value
         | 
| 1617 1848 | 
             
                      case value
         | 
| 1618 | 
            -
                      when  | 
| 1849 | 
            +
                      when AbstractEventFuture
         | 
| 1619 1850 | 
             
                        add_delayed_of value
         | 
| 1620 1851 | 
             
                        value.add_callback_notify_blocked self, nil
         | 
| 1621 1852 | 
             
                        countdown
         | 
| @@ -1651,12 +1882,10 @@ module Concurrent | |
| 1651 1882 |  | 
| 1652 1883 | 
             
                      value = internal_state.value
         | 
| 1653 1884 | 
             
                      case value
         | 
| 1654 | 
            -
                      when  | 
| 1885 | 
            +
                      when AbstractEventFuture
         | 
| 1655 1886 | 
             
                        add_delayed_of value
         | 
| 1656 1887 | 
             
                        value.add_callback_notify_blocked self, nil
         | 
| 1657 1888 | 
             
                        countdown
         | 
| 1658 | 
            -
                      when Event
         | 
| 1659 | 
            -
                        evaluate_to(lambda { raise TypeError, 'cannot flatten to Event' })
         | 
| 1660 1889 | 
             
                      else
         | 
| 1661 1890 | 
             
                        evaluate_to(lambda { raise TypeError, "returned value #{value.inspect} is not a Future" })
         | 
| 1662 1891 | 
             
                      end
         | 
| @@ -1670,8 +1899,9 @@ module Concurrent | |
| 1670 1899 |  | 
| 1671 1900 | 
             
                  private
         | 
| 1672 1901 |  | 
| 1673 | 
            -
                  def initialize(delayed, blockers_count, default_executor)
         | 
| 1902 | 
            +
                  def initialize(delayed, blockers_count, default_executor, run_test)
         | 
| 1674 1903 | 
             
                    super delayed, 1, Future.new(self, default_executor)
         | 
| 1904 | 
            +
                    @RunTest = run_test
         | 
| 1675 1905 | 
             
                  end
         | 
| 1676 1906 |  | 
| 1677 1907 | 
             
                  def process_on_blocker_resolution(future, index)
         | 
| @@ -1682,11 +1912,12 @@ module Concurrent | |
| 1682 1912 | 
             
                      return 0
         | 
| 1683 1913 | 
             
                    end
         | 
| 1684 1914 |  | 
| 1685 | 
            -
                    value | 
| 1686 | 
            -
                     | 
| 1687 | 
            -
             | 
| 1688 | 
            -
             | 
| 1689 | 
            -
                       | 
| 1915 | 
            +
                    value               = internal_state.value
         | 
| 1916 | 
            +
                    continuation_future = @RunTest.call value
         | 
| 1917 | 
            +
             | 
| 1918 | 
            +
                    if continuation_future
         | 
| 1919 | 
            +
                      add_delayed_of continuation_future
         | 
| 1920 | 
            +
                      continuation_future.add_callback_notify_blocked self, nil
         | 
| 1690 1921 | 
             
                    else
         | 
| 1691 1922 | 
             
                      resolve_with internal_state
         | 
| 1692 1923 | 
             
                    end
         | 
| @@ -1805,12 +2036,12 @@ module Concurrent | |
| 1805 2036 | 
             
                class AbstractAnyPromise < BlockedPromise
         | 
| 1806 2037 | 
             
                end
         | 
| 1807 2038 |  | 
| 1808 | 
            -
                class  | 
| 2039 | 
            +
                class AnyResolvedEventPromise < AbstractAnyPromise
         | 
| 1809 2040 |  | 
| 1810 2041 | 
             
                  private
         | 
| 1811 2042 |  | 
| 1812 2043 | 
             
                  def initialize(delayed, blockers_count, default_executor)
         | 
| 1813 | 
            -
                    super delayed, blockers_count,  | 
| 2044 | 
            +
                    super delayed, blockers_count, Event.new(self, default_executor)
         | 
| 1814 2045 | 
             
                  end
         | 
| 1815 2046 |  | 
| 1816 2047 | 
             
                  def resolvable?(countdown, future, index)
         | 
| @@ -1818,16 +2049,16 @@ module Concurrent | |
| 1818 2049 | 
             
                  end
         | 
| 1819 2050 |  | 
| 1820 2051 | 
             
                  def on_resolvable(resolved_future, index)
         | 
| 1821 | 
            -
                    resolve_with  | 
| 2052 | 
            +
                    resolve_with RESOLVED, false
         | 
| 1822 2053 | 
             
                  end
         | 
| 1823 2054 | 
             
                end
         | 
| 1824 2055 |  | 
| 1825 | 
            -
                class  | 
| 2056 | 
            +
                class AnyResolvedFuturePromise < AbstractAnyPromise
         | 
| 1826 2057 |  | 
| 1827 2058 | 
             
                  private
         | 
| 1828 2059 |  | 
| 1829 2060 | 
             
                  def initialize(delayed, blockers_count, default_executor)
         | 
| 1830 | 
            -
                    super delayed, blockers_count,  | 
| 2061 | 
            +
                    super delayed, blockers_count, Future.new(self, default_executor)
         | 
| 1831 2062 | 
             
                  end
         | 
| 1832 2063 |  | 
| 1833 2064 | 
             
                  def resolvable?(countdown, future, index)
         | 
| @@ -1835,7 +2066,7 @@ module Concurrent | |
| 1835 2066 | 
             
                  end
         | 
| 1836 2067 |  | 
| 1837 2068 | 
             
                  def on_resolvable(resolved_future, index)
         | 
| 1838 | 
            -
                    resolve_with  | 
| 2069 | 
            +
                    resolve_with resolved_future.internal_state, false
         | 
| 1839 2070 | 
             
                  end
         | 
| 1840 2071 | 
             
                end
         | 
| 1841 2072 |  |