#ifndef RBIMPL_INTERN_OBJECT_H                       /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_OBJECT_H
/**
 * @file
 * @author     Ruby developers <ruby-core@ruby-lang.org>
 * @copyright  This  file  is   a  part  of  the   programming  language  Ruby.
 *             Permission  is hereby  granted,  to  either redistribute  and/or
 *             modify this file, provided that  the conditions mentioned in the
 *             file COPYING are met.  Consult the file for details.
 * @warning    Symbols   prefixed  with   either  `RBIMPL`   or  `rbimpl`   are
 *             implementation details.   Don't take  them as canon.  They could
 *             rapidly appear then vanish.  The name (path) of this header file
 *             is also an  implementation detail.  Do not expect  it to persist
 *             at the place it is now.  Developers are free to move it anywhere
 *             anytime at will.
 * @note       To  ruby-core:  remember  that   this  header  can  be  possibly
 *             recursively included  from extension  libraries written  in C++.
 *             Do not  expect for  instance `__VA_ARGS__` is  always available.
 *             We assume C99  for ruby itself but we don't  assume languages of
 *             extension libraries.  They could be written in C++98.
 * @brief      Public APIs related to ::rb_cObject.
 */
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/deprecated.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"

RBIMPL_SYMBOL_EXPORT_BEGIN()

/**
 * This macro is (used but) mysterious.  Why on earth do we need this?
 *
 * - `obj != orig` check is done anyways inside of rb_obj_init_copy().
 * - rb_obj_init_copy() returns something.  No need are there to add `, 1`.
 */
#define RB_OBJ_INIT_COPY(obj, orig) \
    ((obj) != (orig) && (rb_obj_init_copy((obj), (orig)), 1))
/** @old{RB_OBJ_INIT_COPY} */
#define OBJ_INIT_COPY(obj, orig) RB_OBJ_INIT_COPY(obj, orig)

/* object.c */

/**
 * Identical to  rb_class_new_instance(), except it passes  the passed keywords
 * if any to the `#initialize` method.
 *
 * @param[in]  argc           Number of objects of `argv`.
 * @param[in]  argv           Arbitrary number of method arguments.
 * @param[in]  klass          An instance of ::rb_cClass.
 * @exception  rb_eTypeError  `klass`'s allocator is undefined.
 * @exception  rb_eException  Any exceptions can happen inside.
 * @return     An allocated new instance of `klass`.
 * @note       This is _the_ implementation of `Object.new`.
 */
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass);

/**
 * Allocates, then initialises an instance of  the given class.  It first calls
 * the passed  class' allocator to  obtain an uninitialised object,  then calls
 * its initialiser with the remaining arguments.
 *
 * @param[in]  argc           Number of objects of `argv`.
 * @param[in]  argv           Arguments passed to `#initialize`.
 * @param[in]  klass          An instance of ::rb_cClass.
 * @exception  rb_eTypeError  `klass`'s allocator is undefined.
 * @exception  rb_eException  Any exceptions can happen inside.
 * @return     An allocated new instance of `klass`.
 */
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass);

/**
 * Identical to rb_class_new_instance(),  except you can specify  how to handle
 * the last element of the given array.
 *
 * @param[in]  argc             Number of objects of `argv`.
 * @param[in]  argv             Arbitrary number of method arguments.
 * @param[in]  klass            An instance of ::rb_cClass.
 * @param[in]  kw_splat         Handling of keyword parameters:
 *   - RB_NO_KEYWORDS           `argv`'s last is not a keyword argument.
 *   - RB_PASS_KEYWORDS         `argv`'s last is a keyword argument.
 *   - RB_PASS_CALLED_KEYWORDS  it depends if there is a passed block.
 * @exception  rb_eTypeError    `klass`'s allocator is undefined.
 * @exception  rb_eException    Any exceptions can happen inside.
 * @return     An allocated new instance of `klass`.
 */
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat);

/**
 * Checks for equality of the passed objects, in terms of `Object#eql?`.
 *
 * @param[in]  lhs          Comparison left hand side.
 * @param[in]  rhs          Comparison right hand side.
 * @retval     non-zero     They are equal.
 * @retval     0            Otherwise.
 * @note       This  function  actually  calls `lhs.eql?(rhs)`  so  you  cannot
 *             implement your class' `#eql?` method using it.
 */
int rb_eql(VALUE lhs, VALUE rhs);

/**
 * Generates a textual representation of the given object.
 *
 * @param[in]  obj  Arbitrary ruby object.
 * @return     An instance of ::rb_cString that represents `obj`.
 * @note       This is  the default  implementation of `Object#to_s`  that each
 *             subclasses want to override.
 */
VALUE rb_any_to_s(VALUE obj);

/**
 * Generates a human-readable textual representation of the given object.  This
 * is  largely similar  to Ruby  level `Object#inspect`  but not  the same;  it
 * additionally escapes the inspection result  so that the string be compatible
 * with that of default internal (or default external, if absent).
 *
 * @param[in]  obj  Arbitrary ruby object.
 * @return     An instance of ::rb_cString that represents `obj`.
 */
VALUE rb_inspect(VALUE obj);

/**
 * Queries if the given object is a direct instance of the given class.
 *
 * @param[in]  obj            Arbitrary ruby object.
 * @param[in]  klass          An instance of ::rb_cModule.
 * @exception  rb_eTypeError  `klass` is neither module nor class.
 * @retval     RUBY_Qtrue     `obj` is an instance of `klass`.
 * @retval     RUBY_Qfalse    Otherwise.
 */
VALUE rb_obj_is_instance_of(VALUE obj, VALUE klass);

/**
 * Queries if the given object is  an instance (of possibly descendants) of the
 * given class.
 *
 * @param[in]  obj            Arbitrary ruby object.
 * @param[in]  klass          An instance of ::rb_cModule.
 * @exception  rb_eTypeError  `klass` is neither module nor class.
 * @retval     RUBY_Qtrue     `obj` is a `klass`.
 * @retval     RUBY_Qfalse    Otherwise.
 */
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass);

/**
 * Allocates an instance of the given class.
 *
 * @param[in]  klass          A class to instantiate.
 * @exception  rb_eTypeError  `klass` is not a class.
 * @return     An allocated, not yet initialised instance of `klass`.
 * @note       It calls  the allocator defined by  rb_define_alloc_func().  You
 *             cannot  use   this  function   to  define  an   allocator.   Use
 *             TypedData_Make_Struct or others, instead.
 * @note       Usually  prefer  rb_class_new_instance() to  rb_obj_alloc()  and
 *             rb_obj_call_init().
 * @see        rb_class_new_instance()
 * @see        rb_obj_call_init()
 * @see        rb_define_alloc_func()
 * @see        #TypedData_Make_Struct
 */
VALUE rb_obj_alloc(VALUE klass);

/**
 * Produces a shallow copy of the given object.  Its list of instance variables
 * are copied, but  not the objects they reference.  It  also copies the frozen
 * value state.
 *
 * @param[in]  obj            Arbitrary ruby object.
 * @exception  rb_eException  `#initialize_copy` can raise anything.
 * @return     A "clone" of `obj`.
 *
 * @internal
 *
 * Unlike ruby-level `Object#clone`, there is no way to control the frozen-ness
 * of the return value.
 */
VALUE rb_obj_clone(VALUE obj);

/**
 * Duplicates  the  given   object.   This  does  almost  the   same  thing  as
 * rb_obj_clone() do.  However  it does not copy the singleton  class (if any).
 * It also doesn't copy frozen-ness.
 *
 * @param[in]  obj            Arbitrary ruby object.
 * @exception  rb_eException  `#initialize_copy` can raise anything.
 * @return     A shallow copy of `obj`.
 */
VALUE rb_obj_dup(VALUE obj);

/**
 * Default   implementation   of  `#initialize_copy`,   `#initialize_dup`   and
 * `#initialize_clone`.  It  does almost  nothing.  Just raises  exceptions for
 * checks.
 *
 * @param[in]  dst              The destination object.
 * @param[in]  src              The source object.
 * @exception  rb_eFrozenError  `dst` is frozen.
 * @exception  rb_eTypeError    `dst` and `src` have different classes.
 * @return     Always returns `dst`.
 */
VALUE rb_obj_init_copy(VALUE src, VALUE dst);

/**
 * Just  calls  rb_obj_freeze_inline() inside.   Does  this  make any  sens  to
 * extension libraries?
 *
 * @param[out]  obj  Object to freeze.
 * @return      Verbatim `obj`.
 */
VALUE rb_obj_freeze(VALUE obj);

RBIMPL_ATTR_PURE()
/**
 * Just calls  RB_OBJ_FROZEN() inside.   Does this make  any sens  to extension
 * libraries?
 *
 * @param[in]  obj          Object in question.
 * @retval     RUBY_Qtrue   Yes it is.
 * @retval     RUBY_Qfalse  No it isn't.
 */
VALUE rb_obj_frozen_p(VALUE obj);

/* gc.c */

/**
 * Finds or  creates an integer  primary key of the  given object.  In  the old
 * days  this  function  was  a  purely  arithmetic  operation  that  maps  the
 * underlying memory  address where the  object resides into a  Ruby's integer.
 * Some time around  2.x this changed.  It no longer  relates its return values
 * to C level pointers.  This function  assigns some random number to the given
 * object  if absent.   The  same number  will be  returned  on all  subsequent
 * requests.  No two active objects share a number.
 *
 * @param[in]  obj  Arbitrary ruby object.
 * @return     An instance of ::rb_cInteger which is an "identifier" of `obj`.
 *
 * @internal
 *
 * The "some  random number" is  in fact a  monotonic-increasing process-global
 * unique integer, much like an  `INTEGER AUTO_INCREMENT PRIMARY KEY` column in
 * a MySQL table.
 */
VALUE rb_obj_id(VALUE obj);

RBIMPL_ATTR_CONST()
/**
 * Identical to rb_obj_id(), except it hesitates from allocating a new instance
 * of ::rb_cInteger.  rb_obj_id() could allocate ::RUBY_T_BIGNUM objects.  That
 * allocation  might  perhaps  impact  negatively.  On  such  situations,  this
 * function  instead returns  one-shot temporary  small integers  that need  no
 * allocations at all.  The values are  guaranteed unique at the moment, but no
 * future promise  is made; could  be reused.  Use of  this API should  be very
 * instant.  It is a failure to store the returned integer to somewhere else.
 *
 * In short it is difficult to use.
 *
 * @param[in]  obj  Arbitrary ruby object.
 * @return     An instance of ::rb_cInteger unique at the moment.
 *
 * @internal
 *
 * This is roughly the old behaviour of rb_obj_id().
 */
VALUE rb_memory_id(VALUE obj);

/* object.c */

RBIMPL_ATTR_PURE()
/**
 * Finds a "real" class.  As the name  implies there are class objects that are
 * surreal.   This function  takes a  class, traverses  its ancestry  tree, and
 * returns  its nearest  ancestor which  is neither  a module  nor a  singleton
 * class.
 *
 * @param[in]  klass        An instance of ::rb_cClass.
 * @retval     RUBY_Qfalse  No real class in `klass`' ancestry tree.
 * @retval     klass        `klass` itself is a real class.
 * @retval     otherwise    Nearest ancestor of `klass` who is real.
 */
VALUE rb_class_real(VALUE klass);

RBIMPL_ATTR_PURE()
/**
 * Determines if the given two modules are relatives.
 *
 * @param[in]  scion          Possible subclass.
 * @param[in]  ascendant      Possible superclass.
 * @exception  rb_eTypeError  `ascendant` is not a module.
 * @retval     RUBY_Qtrue     `scion` inherits, or is equal to `ascendant`.
 * @retval     RUBY_Qfalse    `ascendant` inherits `scion`.
 * @retval     RUBY_Qnil      They are not relatives.
 */
VALUE rb_class_inherited_p(VALUE scion, VALUE ascendant);

RBIMPL_ATTR_PURE()
/**
 * Queries the parent of the given class.
 *
 * @param[in]  klass          A child class.
 * @exception  rb_eTypeError  `klass` is a `Class.allocate`.
 * @retval     RUBY_Qfalse    `klass` has no superclass.
 * @retval     otherwise      `klass`' superclass.
 *
 * @internal
 *
 * Is there any class except ::rb_cBasicObject, that has no superclass?
 */
VALUE rb_class_superclass(VALUE klass);

RBIMPL_ATTR_NONNULL(())
/**
 * Converts an object into another type.  Calls the specified conversion method
 * if necessary.
 *
 * @param[in]  val            An object to convert.
 * @param[in]  type           A value of enum ::ruby_value_type.
 * @param[in]  name           Name to display on error (e.g. "Array").
 * @param[in]  mid            Conversion method (e.g. "to_ary").
 * @exception  rb_eTypeError  Failed to convert.
 * @return     An object of the specified type.
 */
VALUE rb_convert_type(VALUE val, int type, const char *name, const char *mid);

RBIMPL_ATTR_NONNULL(())
/**
 * Identical  to rb_convert_type(),  except it  returns ::RUBY_Qnil  instead of
 * raising  exceptions,  in  case  of  conversion  failure.   It  still  raises
 * exceptions  for various  reasons,  like when  the  conversion method  itself
 * raises, though.
 *
 * @param[in]  val            An object to convert.
 * @param[in]  type           A value of enum ::ruby_value_type.
 * @param[in]  name           Name to display on error (e.g. "Array").
 * @param[in]  mid            Conversion method (e.g. "to_ary").
 * @exception  rb_eTypeError  The `mid` does not generate `type`.
 * @retval     RUBY_Qnil      No conversion defined.
 * @retval     otherwise      An object of the specified type.
 */
VALUE rb_check_convert_type(VALUE val, int type, const char *name, const char *mid);

RBIMPL_ATTR_NONNULL(())
/**
 * Identical to rb_check_convert_type(), except the  return value type is fixed
 * to ::rb_cInteger.
 *
 * @param[in]  val            An object to convert.
 * @param[in]  mid            Conversion method (e.g. "to_ary").
 * @exception  rb_eTypeError  The `mid` does not generate an integer.
 * @retval     RUBY_Qnil      No conversion defined.
 * @retval     otherwise      An instance of ::rb_cInteger.
 */
VALUE rb_check_to_integer(VALUE val, const char *mid);

/**
 * This is complicated.
 *
 *   - When  the passed  object is  already  an instance  of ::rb_cFloat,  just
 *     returns it as-is.
 *
 *   - When  the passed  object is  something  numeric, the  function tries  to
 *     convert it using `#to_f` method.
 *
 *       - If that conversion fails (this happens for instance when the numeric
 *         is a complex) it returns ::RUBY_Qnil.
 *
 *       - Otherwise returns the conversion result.
 *
 *   - Otherwise it also returns ::RUBY_Qnil.
 *
 * @param[in]  val        An object to convert.
 * @retval     RUBY_Qnil  Conversion from `val` to float is undefined.
 * @retval     otherwise  Converted result.
 */
VALUE rb_check_to_float(VALUE val);

/**
 * Identical  to rb_check_to_int(),  except  it raises  in  case of  conversion
 * mismatch.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eTypeError  `#to_int` does not generate an integer.
 * @return     An instance of ::rb_cInteger.
 */
VALUE rb_to_int(VALUE val);

/**
 * Identical to rb_check_to_integer(), except it uses `#to_int` for conversion.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eTypeError  `#to_int` does not return an integer.
 * @retval     RUBY_Qnil      No conversion defined.
 * @retval     otherwise      An instance of ::rb_cInteger.
 */
VALUE rb_check_to_int(VALUE val);

/**
 * This  is the  logic behind  `Kernel#Integer`.  Numeric  types are  converted
 * directly,  with  floating  point   numbers  being  truncated.   Strings  are
 * interpreted  strictly; only  leading/trailing whitespaces,  plus/minus sign,
 * radix  indicators  such  as  `0x`,  digits,  and  underscores  are  allowed.
 * Anything else are converted by first trying `#to_int`, then `#to_i`.
 *
 * This is slightly stricter than `String#to_i`.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eArgError   Malformed `val` passed.
 * @exception  rb_eTypeError  No conversion defined.
 * @return     An instance of ::rb_cInteger.
 */
VALUE rb_Integer(VALUE val);

/**
 * Identical to rb_check_to_float(), except it raises on error.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eTypeError  No conversion defined.
 * @return     An instance of ::rb_cFloat.
 */
VALUE rb_to_float(VALUE val);

/**
 * This  is  the logic  behind  `Kernel#Float`.   Numeric types  are  converted
 * directly  to the  nearest value  that a  Float can  represent.  Strings  are
 * interpreted strictly;  only leading/trailing whitespaces are  allowed except
 * what `strtod` understands.  Anything else are converted using `#to_f`.
 *
 * This is slightly stricter than `String#to_f`.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eArgError   Malformed `val` passed.
 * @exception  rb_eTypeError  No conversion defined.
 * @return     An instance of ::rb_cFloat.
 */
VALUE rb_Float(VALUE val);

/**
 * This is the logic behind  `Kernel#String`.  Arguments are converted by first
 * trying `#to_str`, then `#to_s`.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eTypeError  No conversion defined.
 * @return     An instance of ::rb_cString.
 */
VALUE rb_String(VALUE val);

/**
 * This is the  logic behind `Kernel#Array`.  Arguments are  converted by first
 * trying `#to_ary`,  then `#to_a`,  and if  both failed,  returns an  array of
 * length 1 that contains the passed argument as the sole contents.
 *
 * @param[in]  val  An object to convert.
 * @return     An instance of ::rb_cArray.
 */
VALUE rb_Array(VALUE val);

/**
 * This is  the logic behind  `Kernel#Hash`.  Arguments are converted  by first
 * trying `#to_hash`.  if it failed, and  the argument is either ::RUBY_Qnil or
 * an empty array, returns an empty hash.  Otherwise an exception is raised.
 *
 * @param[in]  val            An object to convert.
 * @exception  rb_eTypeError  No conversion defined.
 * @return     An instance of ::rb_cHash.
 */
VALUE rb_Hash(VALUE val);

RBIMPL_ATTR_NONNULL(())
/**
 * Converts a textual representation of a  real number into a numeric, which is
 * the nearest value that the return type  can represent, of the value that the
 * argument represents.  This is in fact  a 2-in-1 function whose behaviour can
 * be controlled using  the second (mode) argument.  If the  mode is zero, this
 * function is in "historical"  mode which only understands "floating-constant"
 * defined at ISO/IEC 9899:1990 section 6.1.3.1.  If the mode is nonzero, it is
 * in  "extended"  mode,  which  also  accepts  "hexadecimal-floating-constant"
 * defined at ISO/IEC 9899:2018 section 6.4.4.2.
 *
 * @param[in]  str           A textual representation of a real number.
 * @param[in]  mode          Conversion mode, as described above.
 * @exception  rb_eArgError  Malformed `str` passed.
 * @see        https://bugs.ruby-lang.org/issues/2969
 * @note       Null pointers are allowed, and it returns 0.0 then.
 */
double rb_cstr_to_dbl(const char *str, int mode);

/**
 * Identical to rb_cstr_to_dbl(), except it  accepts a Ruby's string instead of
 * C's.
 *
 * @param[in]  str           A textual representation of a real number.
 * @param[in]  mode          Conversion mode, as described in rb_cstr_to_dbl().
 * @exception  rb_eArgError  Malformed `str` passed.
 * @see        https://bugs.ruby-lang.org/issues/2969
 */
double rb_str_to_dbl(VALUE str, int mode);

RBIMPL_SYMBOL_EXPORT_END()

#endif /* RBIMPL_INTERN_OBJECT_H */
