core/fiber.rbs in rbs-2.6.0 vs core/fiber.rbs in rbs-2.7.0.pre.1

- old
+ new

@@ -76,18 +76,126 @@ # the scheduler. # class Fiber < Object # <!-- # rdoc-file=cont.c + # - Fiber.blocking? -> false or 1 + # --> + # Returns `false` if the current fiber is non-blocking. Fiber is non-blocking if + # it was created via passing `blocking: false` to Fiber.new, or via + # Fiber.schedule. + # + # If the current Fiber is blocking, the method returns 1. Future developments + # may allow for situations where larger integers could be returned. + # + # Note that, even if the method returns `false`, Fiber behaves differently only + # if Fiber.scheduler is set in the current thread. + # + # See the "Non-blocking fibers" section in class docs for details. + # + def self.blocking?: () -> untyped + + # <!-- + # rdoc-file=cont.c + # - Fiber.current -> fiber + # --> + # Returns the current fiber. If you are not running in the context of a fiber + # this method will return the root fiber. + # + def self.current: () -> Fiber + + # <!-- + # rdoc-file=cont.c + # - Fiber.current_scheduler -> obj or nil + # --> + # Returns the Fiber scheduler, that was last set for the current thread with + # Fiber.set_scheduler if and only if the current fiber is non-blocking. + # + def self.current_scheduler: () -> untyped? + + # <!-- + # rdoc-file=cont.c + # - Fiber.schedule { |*args| ... } -> fiber + # --> + # The method is *expected* to immediately run the provided block of code in a + # separate non-blocking fiber. + # + # puts "Go to sleep!" + # + # Fiber.set_scheduler(MyScheduler.new) + # + # Fiber.schedule do + # puts "Going to sleep" + # sleep(1) + # puts "I slept well" + # end + # + # puts "Wakey-wakey, sleepyhead" + # + # Assuming MyScheduler is properly implemented, this program will produce: + # + # Go to sleep! + # Going to sleep + # Wakey-wakey, sleepyhead + # ...1 sec pause here... + # I slept well + # + # ...e.g. on the first blocking operation inside the Fiber (`sleep(1)`), the + # control is yielded to the outside code (main fiber), and *at the end of that + # execution*, the scheduler takes care of properly resuming all the blocked + # fibers. + # + # Note that the behavior described above is how the method is *expected* to + # behave, actual behavior is up to the current scheduler's implementation of + # Fiber::SchedulerInterface#fiber method. Ruby doesn't enforce this method to + # behave in any particular way. + # + # If the scheduler is not set, the method raises `RuntimeError (No scheduler is + # available!)`. + # + def self.schedule: () { () -> void } -> Fiber + + # <!-- + # rdoc-file=cont.c + # - Fiber.scheduler -> obj or nil + # --> + # Returns the Fiber scheduler, that was last set for the current thread with Fiber.set_scheduler. + # Returns +nil+ if no scheduler is set (which is the default), and non-blocking fibers' + # + # # behavior is the same as blocking. + # (see "Non-blocking fibers" section in class docs for details about the scheduler concept). + # + def self.scheduler: () -> untyped? + + # <!-- + # rdoc-file=cont.c + # - Fiber.set_scheduler(scheduler) -> scheduler + # --> + # Sets the Fiber scheduler for the current thread. If the scheduler is set, + # non-blocking fibers (created by Fiber.new with `blocking: false`, or by + # Fiber.schedule) call that scheduler's hook methods on potentially blocking + # operations, and the current thread will call scheduler's `close` method on + # finalization (allowing the scheduler to properly manage all non-finished + # fibers). + # + # `scheduler` can be an object of any class corresponding to + # Fiber::SchedulerInterface. Its implementation is up to the user. + # + # See also the "Non-blocking fibers" section in class docs. + # + def self.set_scheduler: (untyped) -> untyped + + # <!-- + # rdoc-file=cont.c # - Fiber.yield(args, ...) -> obj # --> # Yields control back to the context that resumed the fiber, passing along any # arguments that were passed to it. The fiber will resume processing at this # point when #resume is called next. Any arguments passed to the next #resume # will be the value that this Fiber.yield expression evaluates to. # - def self.yield: (*untyped args) -> untyped + def self.yield: (*untyped) -> untyped # <!-- # rdoc-file=cont.c # - Fiber.new(blocking: false) { |*args| ... } -> fiber # --> @@ -108,29 +216,113 @@ # # If `blocking: false` is passed to `Fiber.new`, *and* current thread has a # Fiber.scheduler defined, the Fiber becomes non-blocking (see "Non-blocking # Fibers" section in class docs). # - def initialize: () { () -> untyped } -> void + def initialize: (?blocking: boolish) { (*untyped) -> void } -> void # <!-- # rdoc-file=cont.c - # - fiber.resume(args, ...) -> obj + # - fiber.alive? -> true or false # --> - # Resumes the fiber from the point at which the last Fiber.yield was called, or - # starts running it if it is the first call to #resume. Arguments passed to - # resume will be the value of the Fiber.yield expression or will be passed as - # block parameters to the fiber's block if this is the first #resume. + # Returns true if the fiber can still be resumed (or transferred to). After + # finishing execution of the fiber block this method will always return `false`. # - # Alternatively, when resume is called it evaluates to the arguments passed to - # the next Fiber.yield statement inside the fiber's block or to the block value - # if it runs to completion without any Fiber.yield + def alive?: () -> bool + + # <!-- + # rdoc-file=cont.c + # - fiber.backtrace -> array + # - fiber.backtrace(start) -> array + # - fiber.backtrace(start, count) -> array + # - fiber.backtrace(start..end) -> array + # --> + # Returns the current execution stack of the fiber. `start`, `count` and `end` + # allow to select only parts of the backtrace. # - def resume: (*untyped args) -> untyped + # def level3 + # Fiber.yield + # end + # + # def level2 + # level3 + # end + # + # def level1 + # level2 + # end + # + # f = Fiber.new { level1 } + # + # # It is empty before the fiber started + # f.backtrace + # #=> [] + # + # f.resume + # + # f.backtrace + # #=> ["test.rb:2:in `yield'", "test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'", "test.rb:13:in `block in <main>'"] + # p f.backtrace(1) # start from the item 1 + # #=> ["test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'", "test.rb:13:in `block in <main>'"] + # p f.backtrace(2, 2) # start from item 2, take 2 + # #=> ["test.rb:6:in `level2'", "test.rb:10:in `level1'"] + # p f.backtrace(1..3) # take items from 1 to 3 + # #=> ["test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'"] + # + # f.resume + # + # # It is nil after the fiber is finished + # f.backtrace + # #=> nil + # + def backtrace: (?Integer start, ?Integer count) -> Array[String]? + | (Range[Integer]) -> Array[String]? # <!-- # rdoc-file=cont.c + # - fiber.backtrace_locations -> array + # - fiber.backtrace_locations(start) -> array + # - fiber.backtrace_locations(start, count) -> array + # - fiber.backtrace_locations(start..end) -> array + # --> + # Like #backtrace, but returns each line of the execution stack as a + # Thread::Backtrace::Location. Accepts the same arguments as #backtrace. + # + # f = Fiber.new { Fiber.yield } + # f.resume + # loc = f.backtrace_locations.first + # loc.label #=> "yield" + # loc.path #=> "test.rb" + # loc.lineno #=> 1 + # + def backtrace_locations: (?Integer start, ?Integer count) -> Array[Thread::Backtrace::Location]? + | (Range[Integer]) -> Array[Thread::Backtrace::Location]? + + # <!-- + # rdoc-file=cont.c + # - fiber.blocking? -> true or false + # --> + # Returns `true` if `fiber` is blocking and `false` otherwise. Fiber is + # non-blocking if it was created via passing `blocking: false` to Fiber.new, or + # via Fiber.schedule. + # + # Note that, even if the method returns `false`, the fiber behaves differently + # only if Fiber.scheduler is set in the current thread. + # + # See the "Non-blocking fibers" section in class docs for details. + # + def blocking?: () -> bool + + # <!-- + # rdoc-file=cont.c + # - inspect() + # --> + # + alias inspect to_s + + # <!-- + # rdoc-file=cont.c # - fiber.raise -> obj # - fiber.raise(string) -> obj # - fiber.raise(exception [, string [, array]]) -> obj # --> # Raises an exception in the fiber at the point at which the last `Fiber.yield` @@ -145,9 +337,107 @@ # returns an `Exception` object when sent an `exception` message). The optional # second parameter sets the message associated with the exception, and the third # parameter is an array of callback information. Exceptions are caught by the # `rescue` clause of `begin...end` blocks. # - def raise: () -> untyped - | (string message) -> untyped - | (_Exception exception, ?string message, ?Array[String] backtrace) -> untyped + def raise: (?string msg) -> untyped + | (_Exception, ?string msg, ?Array[string] backtrace) -> untyped + + # <!-- + # rdoc-file=cont.c + # - fiber.resume(args, ...) -> obj + # --> + # Resumes the fiber from the point at which the last Fiber.yield was called, or + # starts running it if it is the first call to #resume. Arguments passed to + # resume will be the value of the Fiber.yield expression or will be passed as + # block parameters to the fiber's block if this is the first #resume. + # + # Alternatively, when resume is called it evaluates to the arguments passed to + # the next Fiber.yield statement inside the fiber's block or to the block value + # if it runs to completion without any Fiber.yield + # + def resume: (*untyped) -> untyped + + # <!-- + # rdoc-file=cont.c + # - to_s() + # --> + # + def to_s: () -> untyped + + # <!-- + # rdoc-file=cont.c + # - fiber.transfer(args, ...) -> obj + # --> + # Transfer control to another fiber, resuming it from where it last stopped or + # starting it if it was not resumed before. The calling fiber will be suspended + # much like in a call to Fiber.yield. + # + # The fiber which receives the transfer call treats it much like a resume call. + # Arguments passed to transfer are treated like those passed to resume. + # + # The two style of control passing to and from fiber (one is #resume and + # Fiber::yield, another is #transfer to and from fiber) can't be freely mixed. + # + # * If the Fiber's lifecycle had started with transfer, it will never be able + # to yield or be resumed control passing, only finish or transfer back. (It + # still can resume other fibers that are allowed to be resumed.) + # * If the Fiber's lifecycle had started with resume, it can yield or transfer + # to another Fiber, but can receive control back only the way compatible + # with the way it was given away: if it had transferred, it only can be + # transferred back, and if it had yielded, it only can be resumed back. + # After that, it again can transfer or yield. + # + # + # If those rules are broken FiberError is raised. + # + # For an individual Fiber design, yield/resume is easier to use (the Fiber just + # gives away control, it doesn't need to think about who the control is given + # to), while transfer is more flexible for complex cases, allowing to build + # arbitrary graphs of Fibers dependent on each other. + # + # Example: + # + # manager = nil # For local var to be visible inside worker block + # + # # This fiber would be started with transfer + # # It can't yield, and can't be resumed + # worker = Fiber.new { |work| + # puts "Worker: starts" + # puts "Worker: Performed #{work.inspect}, transferring back" + # # Fiber.yield # this would raise FiberError: attempt to yield on a not resumed fiber + # # manager.resume # this would raise FiberError: attempt to resume a resumed fiber (double resume) + # manager.transfer(work.capitalize) + # } + # + # # This fiber would be started with resume + # # It can yield or transfer, and can be transferred + # # back or resumed + # manager = Fiber.new { + # puts "Manager: starts" + # puts "Manager: transferring 'something' to worker" + # result = worker.transfer('something') + # puts "Manager: worker returned #{result.inspect}" + # # worker.resume # this would raise FiberError: attempt to resume a transferring fiber + # Fiber.yield # this is OK, the fiber transferred from and to, now it can yield + # puts "Manager: finished" + # } + # + # puts "Starting the manager" + # manager.resume + # puts "Resuming the manager" + # # manager.transfer # this would raise FiberError: attempt to transfer to a yielding fiber + # manager.resume + # + # *produces* + # + # Starting the manager + # Manager: starts + # Manager: transferring 'something' to worker + # Worker: starts + # Worker: Performed "something", transferring back + # Manager: worker returned "Something" + # Resuming the manager + # Manager: finished + # + def transfer: (*untyped) -> untyped end