# <!-- rdoc-file=ractor.rb -->
# Ractor.new makes a new Ractor, which can run in parallel.
#
#     # The simplest ractor
#     r = Ractor.new {puts "I am in Ractor!"}
#     r.join # wait for it to finish
#     # Here, "I am in Ractor!" is printed
#
# Ractors do not share all objects with each other. There are two main benefits
# to this: across ractors, thread-safety concerns such as data-races and
# race-conditions are not possible. The other benefit is parallelism.
#
# To achieve this, object sharing is limited across ractors. For example, unlike
# in threads, ractors can't access all the objects available in other ractors.
# Even objects normally available through variables in the outer scope are
# prohibited from being used across ractors.
#
#     a = 1
#     r = Ractor.new {puts "I am in Ractor! a=#{a}"}
#     # fails immediately with
#     # ArgumentError (can not isolate a Proc because it accesses outer variables (a).)
#
# The object must be explicitly shared:
#     a = 1
#     r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
#
# On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is
# held per ractor, so ractors can perform in parallel without locking each
# other. This is unlike the situation with threads on CRuby.
#
# Instead of accessing shared state, objects should be passed to and from
# ractors by sending and receiving them as messages.
#
#     a = 1
#     r = Ractor.new do
#       a_in_ractor = receive # receive blocks until somebody passes a message
#       puts "I am in Ractor! a=#{a_in_ractor}"
#     end
#     r.send(a)  # pass it
#     r.join
#     # Here, "I am in Ractor! a=1" is printed
#
# In addition to that, any arguments passed to Ractor.new are passed to the
# block and available there as if received by Ractor.receive, and the last block
# value can be received with Ractor#value.
#
# ## Shareable and unshareable objects
#
# When an object is sent to and from a ractor, it's important to understand
# whether the object is shareable or unshareable. Most Ruby objects are
# unshareable objects. Even frozen objects can be unshareable if they contain
# (through their instance variables) unfrozen objects.
#
# Shareable objects are those which can be used by several threads without
# compromising thread-safety, for example numbers, `true` and `false`.
# Ractor.shareable? allows you to check this, and Ractor.make_shareable tries to
# make the object shareable if it's not already, and gives an error if it can't
# do it.
#
#     Ractor.shareable?(1)            #=> true -- numbers and other immutable basic values are shareable
#     Ractor.shareable?('foo')        #=> false, unless the string is frozen due to # frozen_string_literal: true
#     Ractor.shareable?('foo'.freeze) #=> true
#     Ractor.shareable?([Object.new].freeze) #=> false, inner object is unfrozen
#
#     ary = ['hello', 'world']
#     ary.frozen?                 #=> false
#     ary[0].frozen?              #=> false
#     Ractor.make_shareable(ary)
#     ary.frozen?                 #=> true
#     ary[0].frozen?              #=> true
#     ary[1].frozen?              #=> true
#
# When a shareable object is sent (via #send or Ractor.yield), no additional
# processing occurs on it. It just becomes usable by both ractors. When an
# unshareable object is sent, it can be either *copied* or *moved*. The first is
# the default, and it copies the object fully by deep cloning (Object#clone) the
# non-shareable parts of its structure.
#
#     data = ['foo', 'bar'.freeze]
#     r = Ractor.new do
#       data2 = Ractor.receive
#       puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
#     end
#     r.send(data)
#     r.join
#     puts "Outside  : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
#
# This will output something like:
#
#     In ractor: 340, 360, 320
#     Outside  : 380, 400, 320
#
# Note that the object ids of the array and the non-frozen string inside the
# array have changed in the ractor because they are different objects. The
# second array's element, which is a shareable frozen string, is the same
# object.
#
# Deep cloning of objects may be slow, and sometimes impossible. Alternatively,
# `move: true` may be used during sending. This will *move* the unshareable
# object to the receiving ractor, making it inaccessible to the sending ractor.
#
#     data = ['foo', 'bar']
#     r = Ractor.new do
#       data_in_ractor = Ractor.receive
#       puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
#     end
#     r.send(data, move: true)
#     r.join
#     puts "Outside: moved? #{Ractor::MovedObject === data}"
#     puts "Outside: #{data.inspect}"
#
# This will output:
#
#     In ractor: 100, 120
#     Outside: moved? true
#     test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
#
# Notice that even `inspect` (and more basic methods like `__id__`) is
# inaccessible on a moved object.
#
# `Class` and `Module` objects are shareable so the class/module definitions are
# shared between ractors. Ractor objects are also shareable. All operations on
# shareable objects are thread-safe, so the thread-safety property will be kept.
# We can not define mutable shareable objects in Ruby, but C extensions can
# introduce them.
#
# It is prohibited to access (get) instance variables of shareable objects in
# other ractors if the values of the variables aren't shareable. This can occur
# because modules/classes are shareable, but they can have instance variables
# whose values are not. In non-main ractors, it's also prohibited to set
# instance variables on classes/modules (even if the value is shareable).
#
#     class C
#       class << self
#         attr_accessor :tricky
#       end
#     end
#
#     C.tricky = "unshareable".dup
#
#     r = Ractor.new(C) do |cls|
#       puts "I see #{cls}"
#       puts "I can't see #{cls.tricky}"
#       cls.tricky = true # doesn't get here, but this would also raise an error
#     end
#     r.join
#     # I see C
#     # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
# Ractors can access constants if they are shareable. The main Ractor is the
# only one that can access non-shareable constants.
#
#     GOOD = 'good'.freeze
#     BAD = 'bad'.dup
#
#     r = Ractor.new do
#       puts "GOOD=#{GOOD}"
#       puts "BAD=#{BAD}"
#     end
#     r.join
#     # GOOD=good
#     # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
#
#     # Consider the same C class from above
#
#     r = Ractor.new do
#       puts "I see #{C}"
#       puts "I can't see #{C.tricky}"
#     end
#     r.join
#     # I see C
#     # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
# See also the description of `# shareable_constant_value` pragma in [Comments
# syntax](rdoc-ref:syntax/comments.rdoc) explanation.
#
# ## Ractors vs threads
#
# Each ractor has its own main Thread. New threads can be created from inside
# ractors (and, on CRuby, they share the GVL with other threads of this ractor).
#
#     r = Ractor.new do
#       a = 1
#       Thread.new {puts "Thread in ractor: a=#{a}"}.join
#     end
#     r.join
#     # Here "Thread in ractor: a=1" will be printed
#
# ## Note on code examples
#
# In the examples below, sometimes we use the following method to wait for
# ractors that are not currently blocked to finish (or to make progress).
#
#     def wait
#       sleep(0.1)
#     end
#
# It is **only for demonstration purposes** and shouldn't be used in a real
# code. Most of the time, #join is used to wait for ractors to finish.
#
# ## Reference
#
# See [Ractor design doc](rdoc-ref:ractor.md) for more details.
#
class Ractor
  # <!--
  #   rdoc-file=ractor.rb
  #   - _require(feature)
  # -->
  # internal method
  #
  def self._require: (String feature) -> bool

  # <!--
  #   rdoc-file=ractor.rb
  #   - [](sym)
  # -->
  # get a value from ractor-local storage of current Ractor
  #
  def self.[]: (Symbol) -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - []=(sym, val)
  # -->
  # set a value in ractor-local storage of current Ractor
  #
  def self.[]=: (Symbol, untyped) -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - count()
  # -->
  # Returns the number of Ractors currently running or blocking (waiting).
  #
  #     Ractor.count                   #=> 1
  #     r = Ractor.new(name: 'example') { Ractor.receive }
  #     Ractor.count                   #=> 2 (main + example ractor)
  #     r << 42                        # r's Ractor.receive will resume
  #     r.join                         # wait for r's termination
  #     Ractor.count                   #=> 1
  #
  def self.count: () -> Integer

  # <!--
  #   rdoc-file=ractor.rb
  #   - current()
  # -->
  # Returns the currently executing Ractor.
  #
  #     Ractor.current #=> #<Ractor:#1 running>
  #
  def self.current: () -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - main()
  # -->
  # returns main ractor
  #
  def self.main: () -> Ractor

  # <!--
  #   rdoc-file=ractor.rb
  #   - main?()
  # -->
  # return true if the current ractor is main ractor
  #
  def self.main?: () -> boolish

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.make_shareable(obj, copy: false) -> shareable_obj
  # -->
  # Make `obj` shareable between ractors.
  #
  # `obj` and all the objects it refers to will be frozen, unless they are already
  # shareable.
  #
  # If `copy` keyword is `true`, it will copy objects before freezing them, and
  # will not modify `obj` or its internal objects.
  #
  # Note that the specification and implementation of this method are not mature
  # and may be changed in the future.
  #
  #     obj = ['test']
  #     Ractor.shareable?(obj)     #=> false
  #     Ractor.make_shareable(obj) #=> ["test"]
  #     Ractor.shareable?(obj)     #=> true
  #     obj.frozen?                #=> true
  #     obj[0].frozen?             #=> true
  #
  #     # Copy vs non-copy versions:
  #     obj1 = ['test']
  #     obj1s = Ractor.make_shareable(obj1)
  #     obj1.frozen?                        #=> true
  #     obj1s.object_id == obj1.object_id   #=> true
  #     obj2 = ['test']
  #     obj2s = Ractor.make_shareable(obj2, copy: true)
  #     obj2.frozen?                        #=> false
  #     obj2s.frozen?                       #=> true
  #     obj2s.object_id == obj2.object_id   #=> false
  #     obj2s[0].object_id == obj2[0].object_id #=> false
  #
  # See also the "Shareable and unshareable objects" section in the Ractor class
  # docs.
  #
  def self.make_shareable: [T] (T obj, ?copy: boolish) -> T

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.new(*args, name: nil) {|*args| block } -> ractor
  # -->
  # Create a new Ractor with args and a block.
  #
  # The given block (Proc) will be isolated (can't access any outer variables).
  # `self` inside the block will refer to the current Ractor.
  #
  #     r = Ractor.new { puts "Hi, I am #{self.inspect}" }
  #     r.join
  #     # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
  #
  # Any `args` passed are propagated to the block arguments by the same rules as
  # objects sent via #send/Ractor.receive. If an argument in `args` is not
  # shareable, it will be copied (via deep cloning, which might be inefficient).
  #
  #     arg = [1, 2, 3]
  #     puts "Passing: #{arg} (##{arg.object_id})"
  #     r = Ractor.new(arg) {|received_arg|
  #       puts "Received: #{received_arg} (##{received_arg.object_id})"
  #     }
  #     r.join
  #     # Prints:
  #     #   Passing: [1, 2, 3] (#280)
  #     #   Received: [1, 2, 3] (#300)
  #
  # Ractor's `name` can be set for debugging purposes:
  #
  #     r = Ractor.new(name: 'my ractor') {}; r.join
  #     p r
  #     #=> #<Ractor:#3 my ractor test.rb:1 terminated>
  #
  def self.new: (*untyped args, ?name: string) { (?) -> untyped } -> Ractor

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.receive -> obj
  # -->
  # Receive a message from the default port.
  #
  def self.receive: () -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - recv()
  # -->
  #
  alias self.recv self.receive

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.select(*ports) -> [...]
  # -->
  # TBD
  #
  def self.select: (?) -> Array[untyped]

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.shareable?(obj) -> true | false
  # -->
  # Checks if the object is shareable by ractors.
  #
  #     Ractor.shareable?(1)            #=> true -- numbers and other immutable basic values are frozen
  #     Ractor.shareable?('foo')        #=> false, unless the string is frozen due to # frozen_string_literal: true
  #     Ractor.shareable?('foo'.freeze) #=> true
  #
  # See also the "Shareable and unshareable objects" section in the Ractor class
  # docs.
  #
  def self.shareable?: (untyped obj) -> bool

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.shareable_proc(self: nil){} -> shareable proc
  # -->
  # It returns shareable Proc object. The Proc object is shareable and the self in
  # a block will be replaced with the value passed via `self:` keyword.
  #
  # In a shareable Proc, you can not access to the outer variables.
  #
  #     a = 42
  #     Ractor.shareable_proc{ p a }
  #     #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError)
  #
  # The `self` should be a shareable object
  #
  #     Ractor.shareable_proc(self: self){}
  #     #=> self should be shareable: main (Ractor::IsolationError)
  #
  def self.shareable_proc: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
                         | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.shareable_proc{} -> shareable proc
  # -->
  # Same as Ractor.shareable_proc, but returns lambda proc.
  #
  def self.shareable_lambda: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
                           | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T

  # <!--
  #   rdoc-file=ractor.rb
  #   - Ractor.store_if_absent(key){ init_block }
  # -->
  # If the corresponding value is not set, yield a value with init_block and store
  # the value in thread-safe manner. This method returns corresponding stored
  # value.
  #
  #     (1..10).map{
  #       Thread.new(it){|i|
  #         Ractor.store_if_absent(:s){ f(); i }
  #         #=> return stored value of key :s
  #       }
  #     }.map(&:value).uniq.size #=> 1 and f() is called only once
  #
  def self.store_if_absent: [A] (Symbol) { (nil) -> A } -> A

  # <!--
  #   rdoc-file=ractor.rb
  #   - <<(...)
  # -->
  #
  alias << send

  # <!--
  #   rdoc-file=ractor.rb
  #   - [](sym)
  # -->
  # get a value from ractor-local storage for current Ractor Obsolete and use
  # Ractor.[] instead.
  #
  %a{deprecated: Use Ractor.[] instead}
  def []: (interned sym) -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - []=(sym, val)
  # -->
  # set a value in ractor-local storage for current Ractor Obsolete and use
  # Ractor.[]= instead.
  #
  %a{deprecated: Use Ractor.[]= instead}
  def []=: [T] (interned sym, T val) -> T

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.default_port -> port object
  # -->
  # return default port of the Ractor.
  #
  def default_port: () -> Port[untyped]

  # <!--
  #   rdoc-file=ractor.rb
  #   - inspect()
  # -->
  #
  def inspect: () -> String

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.join -> self
  # -->
  # Wait for the termination of the Ractor. If the Ractor was aborted (terminated
  # with an exception), Ractor#value is called to raise an exception.
  #
  #     Ractor.new{}.join #=> ractor
  #
  #     Ractor.new{ raise "foo" }.join
  #     #=> raise an exception "foo (RuntimeError)"
  #
  def join: () -> self

  # <!--
  #   rdoc-file=ractor.rb
  #   - name()
  # -->
  # The name set in Ractor.new, or `nil`.
  #
  def name: () -> String?

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.monitor(port) -> self
  # -->
  # Register port as a monitoring port. If the ractor terminated, the port
  # received a Symbol object. :exited will be sent if the ractor terminated
  # without an exception. :aborted will be sent if the ractor terminated with a
  # exception.
  #
  #     r = Ractor.new{ some_task() }
  #     r.monitor(port = Ractor::Port.new)
  #     port.receive #=> :exited and r is terminated
  #
  #     r = Ractor.new{ raise "foo" }
  #     r.monitor(port = Ractor::Port.new)
  #     port.receive #=> :terminated and r is terminated with an exception "foo"
  #
  def monitor: [T < Symbol] (Port[T]) -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.send(msg) -> self
  # -->
  # It is equivalent to default_port.send(msg)
  #
  def send: (untyped obj, ?move: boolish) -> Ractor

  # <!--
  #   rdoc-file=ractor.rb
  #   - to_s()
  # -->
  #
  alias to_s inspect

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.unmonitor(port) -> self
  # -->
  # Unregister port from the monitoring ports.
  #
  def unmonitor: (Port[untyped]) -> self

  # <!--
  #   rdoc-file=ractor.rb
  #   - ractor.value -> obj
  # -->
  # Waits for `ractor` to complete, using #join, and return its value or raise the
  # exception which terminated the Ractor. The value will not be copied even if it
  # is unshareable object. Therefore at most 1 Ractor can get a value.
  #
  #     r = Ractor.new{ [1, 2] }
  #     r.value #=> [1, 2] (unshareable object)
  #
  #     Ractor.new(r){|r| r.value} #=> Ractor::Error
  #
  def value: () -> untyped

  private

  # <!--
  #   rdoc-file=ractor.rb
  #   - receive()
  # -->
  # same as Ractor.receive
  #
  def receive: () -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - receive_if(&b)
  # -->
  # same as Ractor.receive_if
  #
  def receive_if: () { (untyped) -> boolish } -> untyped

  # <!--
  #   rdoc-file=ractor.rb
  #   - recv()
  # -->
  #
  alias recv receive

  # <!-- rdoc-file=ractor.c -->
  # Raised when an attempt is made to send a message to a closed port, or to
  # retrieve a message from a closed and empty port. Ports may be closed
  # explicitly with Ractor#close_outgoing/close_incoming and are closed implicitly
  # when a Ractor terminates.
  #
  #     r = Ractor.new { sleep(500) }
  #     r.close_outgoing
  #     r.take # Ractor::ClosedError
  #
  # ClosedError is a descendant of StopIteration, so the closing of the ractor
  # will break the loops without propagating the error:
  #
  #     r = Ractor.new do
  #       loop do
  #         msg = receive # raises ClosedError and loop traps it
  #         puts "Received: #{msg}"
  #       end
  #       puts "loop exited"
  #     end
  #
  #     3.times{|i| r << i}
  #     r.close_incoming
  #     r.take
  #     puts "Continue successfully"
  #
  # This will print:
  #
  #     Received: 0
  #     Received: 1
  #     Received: 2
  #     loop exited
  #     Continue successfully
  #
  class ClosedError < StopIteration
  end

  # <!-- rdoc-file=ractor.c -->
  # The parent class of Ractor-related error classes.
  #
  class Error < RuntimeError
  end

  # <!-- rdoc-file=ractor.c -->
  # Raised on attempt to make a Ractor-unshareable object Ractor-shareable.
  #
  class IsolationError < Ractor::Error
  end

  # <!-- rdoc-file=ractor.c -->
  # Raised on an attempt to access an object which was moved in Ractor#send or
  # Ractor.yield.
  #
  #     r = Ractor.new { sleep }
  #
  #     ary = [1, 2, 3]
  #     r.send(ary, move: true)
  #     ary.inspect
  #     # Ractor::MovedError (can not send any methods to a moved object)
  #
  class MovedError < Ractor::Error
  end

  # <!-- rdoc-file=ractor.c -->
  # A special object which replaces any value that was moved to another ractor in
  # Ractor#send or Ractor.yield. Any attempt to access the object results in
  # Ractor::MovedError.
  #
  #     r = Ractor.new { receive }
  #
  #     ary = [1, 2, 3]
  #     r.send(ary, move: true)
  #     p Ractor::MovedObject === ary
  #     # => true
  #     ary.inspect
  #     # Ractor::MovedError (can not send any methods to a moved object)
  #
  class MovedObject < BasicObject
    # <!--
    #   rdoc-file=ractor.c
    #   - !(*args)
    # -->
    #
    def !: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - !=(*args)
    # -->
    #
    def !=: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - ==(*args)
    # -->
    #
    def ==: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - __id__(*args)
    # -->
    #
    def __id__: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - __send__(*args)
    # -->
    #
    def __send__: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - equal?(*args)
    # -->
    #
    def equal?: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - instance_eval(*args)
    # -->
    #
    def instance_eval: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - instance_exec(*args)
    # -->
    #
    def instance_exec: (*untyped) -> untyped

    # <!--
    #   rdoc-file=ractor.c
    #   - method_missing(*args)
    # -->
    #
    def method_missing: (*untyped) -> untyped
  end

  # <!-- rdoc-file=ractor.rb -->
  # Port objects transmit messages between Ractors.
  #
  class Port[T = untyped]
    # <!--
    #   rdoc-file=ractor.rb
    #   - <<(obj, move: false)
    # -->
    #
    alias << send

    # <!--
    #   rdoc-file=ractor.rb
    #   - port.close
    # -->
    # Close the port. On the closed port, sending is not prohibited. Receiving is
    # also not allowed if there is no sent messages arrived before closing.
    #
    #     port = Ractor::Port.new
    #     Ractor.new port do |port|
    #       port.send 1 # OK
    #       port.send 2 # OK
    #       port.close
    #       port.send 3 # raise Ractor::ClosedError
    #     end
    #
    #     port.receive #=> 1
    #     port.receive #=> 2
    #     port.receive #=> raise Ractor::ClosedError
    #
    # Now, only a Ractor which creates the port is allowed to close ports.
    #
    #     port = Ractor::Port.new
    #     Ractor.new port do |port|
    #       port.close #=> closing port by other ractors is not allowed (Ractor::Error)
    #     end.join
    #
    def close: () -> void

    # <!--
    #   rdoc-file=ractor.rb
    #   - port.closed? -> true/false
    # -->
    # Return the port is closed or not.
    #
    def closed?: () -> bool

    # <!--
    #   rdoc-file=ractor.rb
    #   - port.inspect -> string
    # -->
    #
    def inspect: () -> String

    # <!--
    #   rdoc-file=ractor.rb
    #   - port.receive -> msg
    # -->
    # Receive a message to the port (which was sent there by Port#send).
    #
    #     port = Ractor::Port.new
    #     r = Ractor.new port do |port|
    #       port.send('message1')
    #     end
    #
    #     v1 = port.receive
    #     puts "Received: #{v1}"
    #     r.join
    #     # Here will be printed: "Received: message1"
    #
    # The method blocks if the message queue is empty.
    #
    #     port = Ractor::Port.new
    #     r = Ractor.new port do |port|
    #       wait
    #       puts "Still not received"
    #       port.send('message1')
    #       wait
    #       puts "Still received only one"
    #       port.send('message2')
    #     end
    #     puts "Before first receive"
    #     v1 = port.receive
    #     puts "Received: #{v1}"
    #     v2 = port.receive
    #     puts "Received: #{v2}"
    #     r.join
    #
    # Output:
    #
    #     Before first receive
    #     Still not received
    #     Received: message1
    #     Still received only one
    #     Received: message2
    #
    # If close_incoming was called on the ractor, the method raises
    # Ractor::ClosedError if there are no more messages in the message queue:
    #
    #     port = Ractor::Port.new
    #     port.close
    #     port.receive #=> raise Ractor::ClosedError
    #
    def receive: () -> T

    # <!--
    #   rdoc-file=ractor.rb
    #   - port.send(msg, move: false) -> self
    # -->
    # Send a message to a port to be accepted by port.receive.
    #
    #     port = Ractor::Port.new
    #     r = Ractor.new do
    #       r.send 'message'
    #     end
    #     value = port.receive
    #     puts "Received #{value}"
    #     # Prints: "Received: message"
    #
    # The method is non-blocking (will return immediately even if the ractor is not
    # ready to receive anything):
    #
    #     port = Ractor::Port.new
    #     r = Ractor.new(port) do |port|
    #       port.send 'test'}
    #       puts "Sent successfully"
    #       # Prints: "Sent successfully" immediately
    #     end
    #
    # An attempt to send to a port which already closed its execution will raise
    # Ractor::ClosedError.
    #
    #     r = Ractor.new {Ractor::Port.new}
    #     r.join
    #     p r
    #     # "#<Ractor:#6 (irb):23 terminated>"
    #     port = r.value
    #     port.send('test') # raise Ractor::ClosedError
    #
    # If the `obj` is unshareable, by default it will be copied into the receiving
    # ractor by deep cloning.
    #
    # If the object is shareable, it only send a reference to the object without
    # cloning.
    #
    def send: (T obj, ?move: boolish) -> self

    private

    # <!--
    #   rdoc-file=ractor_sync.c
    #   - Ractor::Port.new  -> new_port
    # -->
    # Returns a new Ractor::Port object.
    #
    def initialize: () -> void

    def initialize_copy: (untyped) -> untyped
  end

  # <!-- rdoc-file=ractor.c -->
  # Raised on attempt to Ractor#take if there was an uncaught exception in the
  # Ractor. Its `cause` will contain the original exception, and `ractor` is the
  # original ractor it was raised in.
  #
  #     r = Ractor.new { raise "Something weird happened" }
  #
  #     begin
  #       r.take
  #     rescue => e
  #       p e             # => #<Ractor::RemoteError: thrown by remote Ractor.>
  #       p e.ractor == r # => true
  #       p e.cause       # => #<RuntimeError: Something weird happened>
  #     end
  #
  class RemoteError < Ractor::Error
    # <!-- rdoc-file=ractor.rb -->
    # The Ractor an uncaught exception is raised in.
    #
    def ractor: () -> Ractor
  end

  # <!-- rdoc-file=ractor.c -->
  # Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
  #
  class UnsafeError < Ractor::Error
  end

  %a{annotate:rdoc:skip}
  class Selector
  end
end
