# <!-- rdoc-file=gc.c -->
# The ObjectSpace module contains a number of routines that interact with the
# garbage collection facility and allow you to traverse all living objects with
# an iterator.
#
# ObjectSpace also provides support for object finalizers, procs that will be
# called after a specific object was destroyed by garbage collection.  See the
# documentation for `ObjectSpace.define_finalizer` for important information on
# how to use this method correctly.
#
#     a = "A"
#     b = "B"
#
#     ObjectSpace.define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
#     ObjectSpace.define_finalizer(b, proc {|id| puts "Finalizer two on #{id}" })
#
#     a = nil
#     b = nil
#
# *produces:*
#
#     Finalizer two on 537763470
#     Finalizer one on 537763480
#
%a{annotate:rdoc:source:from=gc.c}
module ObjectSpace
  # <!--
  #   rdoc-file=gc.c
  #   - _id2ref(p1)
  # -->
  #
  %a{deprecated}
  def self._id2ref: (Integer id) -> untyped

  # <!--
  #   rdoc-file=gc.c
  #   - ObjectSpace.count_objects([result_hash]) -> hash
  # -->
  # Counts all objects grouped by type.
  #
  # It returns a hash, such as:
  #     {
  #       :TOTAL=>10000,
  #       :FREE=>3011,
  #       :T_OBJECT=>6,
  #       :T_CLASS=>404,
  #       # ...
  #     }
  #
  # The contents of the returned hash are implementation specific. It may be
  # changed in future.
  #
  # The keys starting with `:T_` means live objects. For example, `:T_ARRAY` is
  # the number of arrays. `:FREE` means object slots which is not used now.
  # `:TOTAL` means sum of above.
  #
  # If the optional argument `result_hash` is given, it is overwritten and
  # returned. This is intended to avoid probe effect.
  #
  #     h = {}
  #     ObjectSpace.count_objects(h)
  #     puts h
  #     # => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
  #
  # This method is only expected to work on C Ruby.
  #
  def self.count_objects: (?Hash[Symbol, Integer] result_hash) -> Hash[Symbol, Integer]

  # <!--
  #   rdoc-file=gc.c
  #   - ObjectSpace.define_finalizer(obj, aProc=proc())
  # -->
  # Adds *aProc* as a finalizer, to be called after *obj* was destroyed. The
  # object ID of the *obj* will be passed as an argument to *aProc*. If *aProc* is
  # a lambda or method, make sure it can be called with a single argument.
  #
  # The return value is an array `[0, aProc]`.
  #
  # The two recommended patterns are to either create the finaliser proc in a
  # non-instance method where it can safely capture the needed state, or to use a
  # custom callable object that stores the needed state explicitly as instance
  # variables.
  #
  #     class Foo
  #       def initialize(data_needed_for_finalization)
  #         ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
  #       end
  #
  #       def self.create_finalizer(data_needed_for_finalization)
  #         proc {
  #           puts "finalizing #{data_needed_for_finalization}"
  #         }
  #       end
  #     end
  #
  #     class Bar
  #      class Remover
  #         def initialize(data_needed_for_finalization)
  #           @data_needed_for_finalization = data_needed_for_finalization
  #         end
  #
  #         def call(id)
  #           puts "finalizing #{@data_needed_for_finalization}"
  #         end
  #       end
  #
  #       def initialize(data_needed_for_finalization)
  #         ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
  #       end
  #     end
  #
  # Note that if your finalizer references the object to be finalized it will
  # never be run on GC, although it will still be run at exit. You will get a
  # warning if you capture the object to be finalized as the receiver of the
  # finalizer.
  #
  #     class CapturesSelf
  #       def initialize(name)
  #         ObjectSpace.define_finalizer(self, proc {
  #           # this finalizer will only be run on exit
  #           puts "finalizing #{name}"
  #         })
  #       end
  #     end
  #
  # Also note that finalization can be unpredictable and is never guaranteed to be
  # run except on exit.
  #
  def self.define_finalizer: (untyped obj, ^(Integer id) -> void aProc) -> [ Integer, Proc ]
                           | (untyped obj) { (Integer id) -> void } -> [ Integer, Proc ]

  # <!--
  #   rdoc-file=gc.c
  #   - ObjectSpace.each_object([module]) {|obj| ... } -> integer
  #   - ObjectSpace.each_object([module])              -> an_enumerator
  # -->
  # Calls the block once for each living, nonimmediate object in this Ruby
  # process. If *module* is specified, calls the block for only those classes or
  # modules that match (or are a subclass of) *module*. Returns the number of
  # objects found. Immediate objects (such as `Fixnum`s, static `Symbol`s `true`,
  # `false` and `nil`) are never returned.
  #
  # If no block is given, an enumerator is returned instead.
  #
  #     Job = Class.new
  #     jobs = [Job.new, Job.new]
  #     count = ObjectSpace.each_object(Job) {|x| p x }
  #     puts "Total count: #{count}"
  #
  # *produces:*
  #
  #     #<Job:0x000000011d6cbbf0>
  #     #<Job:0x000000011d6cbc68>
  #      Total count: 2
  #
  # Due to a current Ractor implementation issue, this method does not yield
  # Ractor-unshareable objects when the process is in multi-Ractor mode.
  # Multi-ractor mode is enabled when `Ractor.new` has been called for the first
  # time. See https://bugs.ruby-lang.org/issues/19387 for more information.
  #
  #     a = 12345678987654321 # shareable
  #     b = [].freeze # shareable
  #     c = {} # not shareable
  #     ObjectSpace.each_object {|x| x } # yields a, b, and c
  #     Ractor.new {} # enter multi-Ractor mode
  #     ObjectSpace.each_object {|x| x } # does not yield c
  #
  def self.each_object: (?Module `module`) -> Enumerator[untyped, Integer]
                      | (?Module `module`) { (untyped obj) -> void } -> Integer

  # <!--
  #   rdoc-file=gc.rb
  #   - garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true)
  # -->
  # Alias of GC.start
  #
  def self.garbage_collect: (?full_mark: bool, ?immediate_mark: bool, ?immediate_sweep: bool) -> void

  # <!--
  #   rdoc-file=gc.c
  #   - ObjectSpace.undefine_finalizer(obj)
  # -->
  # Removes all finalizers for *obj*.
  #
  def self.undefine_finalizer: [X] (X obj) -> X

  private

  # <!--
  #   rdoc-file=gc.rb
  #   - garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true)
  # -->
  # Alias of GC.start
  #
  def garbage_collect: (?full_mark: bool, ?immediate_mark: bool, ?immediate_sweep: bool) -> void
end
